• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDECore

  • kdecore
  • localization
kuitsemantics.cpp
Go to the documentation of this file.
1/* This file is part of the KDE libraries
2 Copyright (C) 2007 Chusslove Illich <caslav.ilic@gmx.net>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18*/
19
20#include <kuitsemantics_p.h>
21
22#include <config.h>
23
24#include <QHash>
25#include <QSet>
26#include <QRegExp>
27#include <QStack>
28#include <QXmlStreamReader>
29#include <QStringList>
30#include <QPair>
31#include <QDir>
32
33#include <kdebug.h>
34#include <kglobal.h>
35#include <kcatalog_p.h>
36#include <kuitformats_p.h>
37#include <klocale.h>
38
39#define QL1S(x) QLatin1String(x)
40
41// Truncates string, for output of long messages.
42// (But don't truncate too much otherwise it's impossible to determine
43// which message is faulty if many messages start with the same beginning).
44static QString shorten (const QString &str)
45{
46 const int maxlen = 80;
47 if (str.length() <= maxlen)
48 return str;
49 else
50 return str.left(maxlen).append(QLatin1String("..."));
51}
52
53// Custom entity resolver for QXmlStreamReader.
54class KuitEntityResolver : public QXmlStreamEntityResolver
55{
56 public:
57
58 void setEntities (const QHash<QString, QString> &entities)
59 {
60 entityMap = entities;
61 }
62
63 QString resolveUndeclaredEntity (const QString &name)
64 {
65 QString value = entityMap.value(name);
66 // This will return empty string if the entity name is not known,
67 // which will make QXmlStreamReader signal unknown entity error.
68 return value;
69 }
70
71 private:
72
73 QHash<QString, QString> entityMap;
74};
75
76// -----------------------------------------------------------------------------
77// All the tag, attribute, and context marker element enums.
78namespace Kuit {
79
80 namespace Tag { // tag names
81 typedef enum {
82 None,
83 TopLong, TopShort,
84 Title, Subtitle, Para, List, Item, Note, Warning, Link,
85 Filename, Application, Command, Resource, Icode, Bcode, Shortcut,
86 Interface, Emphasis, Placeholder, Email, Numid, Envar, Message, Nl,
87 NumIntg, NumReal // internal helpers for numbers, not part of DTD
88 } Var;
89 }
90
91 namespace Att { // tag attribute names
92 typedef enum {
93 None,
94 Ctx, Url, Address, Section, Label, Strong,
95 Width, Fill // internal helpers for numbers, not part of DTD
96 } Var;
97 }
98
99 namespace Rol { // semantic roles
100 typedef enum {
101 None,
102 Action, Title, Option, Label, Item, Info
103 } Var;
104 }
105
106 namespace Cue { // interface subcues
107 typedef enum {
108 None,
109 Button, Inmenu, Intoolbar,
110 Window, Menu, Tab, Group, Column, Row,
111 Slider, Spinbox, Listbox, Textbox, Chooser,
112 Check, Radio,
113 Inlistbox, Intable, Inrange, Intext,
114 Tooltip, Whatsthis, Status, Progress, Tipoftheday, Credit, Shell
115 } Var;
116 }
117
118 namespace Fmt { // visual formats
119 typedef enum {
120 None, Plain, Rich, Term
121 } Var;
122 }
123
124 typedef Tag::Var TagVar;
125 typedef Att::Var AttVar;
126 typedef Rol::Var RolVar;
127 typedef Cue::Var CueVar;
128 typedef Fmt::Var FmtVar;
129}
130
131// -----------------------------------------------------------------------------
132// All the global data.
133
134class KuitSemanticsStaticData
135{
136 public:
137
138 QHash<QString, Kuit::TagVar> knownTags;
139 QHash<QString, Kuit::AttVar> knownAtts;
140 QHash<QString, Kuit::FmtVar> knownFmts;
141 QHash<QString, Kuit::RolVar> knownRols;
142 QHash<QString, Kuit::CueVar> knownCues;
143
144 QHash<Kuit::TagVar, QSet<Kuit::TagVar> > tagSubs;
145 QHash<Kuit::TagVar, QSet<Kuit::AttVar> > tagAtts;
146 QHash<Kuit::RolVar, QSet<Kuit::CueVar> > rolCues;
147
148 QHash<Kuit::RolVar, QHash<Kuit::CueVar, Kuit::FmtVar> > defFmts;
149
150 QHash<Kuit::TagVar, QString> tagNames;
151
152 QSet<QString> qtHtmlTagNames;
153
154 QHash<Kuit::TagVar, int> leadingNewlines;
155
156 QHash<QString, QString> xmlEntities;
157 QHash<QString, QString> xmlEntitiesInverse;
158 KuitEntityResolver xmlEntityResolver;
159
160 KuitSemanticsStaticData ();
161};
162
163KuitSemanticsStaticData::KuitSemanticsStaticData ()
164{
165 // Setup known tag names, attributes, and subtags.
166 // A "lax" version of the DTD.
167 #undef SETUP_TAG
168 #define SETUP_TAG(tag, name, atts, subs) do { \
169 knownTags.insert(QString::fromLatin1(name), Kuit::Tag::tag); \
170 tagNames.insert(Kuit::Tag::tag, QString::fromLatin1(name)); \
171 { \
172 using namespace Kuit::Att; \
173 tagAtts[Kuit::Tag::tag] << atts; \
174 } \
175 { \
176 using namespace Kuit::Tag; \
177 tagSubs[Kuit::Tag::tag] << subs << NumIntg << NumReal; \
178 } \
179 } while (0)
180
181 #undef INLINES
182 #define INLINES \
183 Filename << Link << Application << Command << Resource << Icode << \
184 Shortcut << Interface << Emphasis << Placeholder << Email << \
185 Numid << Envar << Nl
186
187 SETUP_TAG(TopLong, "kuit", Ctx, Title << Subtitle << Para);
188 SETUP_TAG(TopShort, "kuil", Ctx, INLINES << Note << Warning << Message);
189
190 SETUP_TAG(Title, "title", None, INLINES);
191 SETUP_TAG(Subtitle, "subtitle", None, INLINES);
192 SETUP_TAG(Para, "para", None,
193 INLINES << Note << Warning << Message << List);
194 SETUP_TAG(List, "list", None, Item);
195 SETUP_TAG(Item, "item", None, INLINES << Note << Warning << Message);
196
197 SETUP_TAG(Note, "note", Label, INLINES);
198 SETUP_TAG(Warning, "warning", Label, INLINES);
199 SETUP_TAG(Filename, "filename", None, Envar << Placeholder);
200 SETUP_TAG(Link, "link", Url, None);
201 SETUP_TAG(Application, "application", None, None);
202 SETUP_TAG(Command, "command", Section, None);
203 SETUP_TAG(Resource, "resource", None, None);
204 SETUP_TAG(Icode, "icode", None, Envar << Placeholder);
205 SETUP_TAG(Bcode, "bcode", None, None);
206 SETUP_TAG(Shortcut, "shortcut", None, None);
207 SETUP_TAG(Interface, "interface", None, None);
208 SETUP_TAG(Emphasis, "emphasis", Strong, None);
209 SETUP_TAG(Placeholder, "placeholder", None, None);
210 SETUP_TAG(Email, "email", Address, None);
211 SETUP_TAG(Envar, "envar", None, None);
212 SETUP_TAG(Message, "message", None, None);
213 SETUP_TAG(Numid, "numid", None, None);
214 SETUP_TAG(Nl, "nl", None, None);
215 // Internal, not part of DTD.
216 SETUP_TAG(NumIntg, KUIT_NUMINTG, Width << Fill, None);
217 SETUP_TAG(NumReal, KUIT_NUMREAL, Width << Fill, None);
218
219 // Setup known attribute names.
220 #undef SETUP_ATT
221 #define SETUP_ATT(att, name) do { \
222 knownAtts.insert(QString::fromLatin1(name), Kuit::Att::att); \
223 } while (0)
224 SETUP_ATT(Ctx, "ctx");
225 SETUP_ATT(Url, "url");
226 SETUP_ATT(Address, "address");
227 SETUP_ATT(Section, "section");
228 SETUP_ATT(Label, "label");
229 SETUP_ATT(Strong, "strong");
230 // Internal, not part of DTD.
231 SETUP_ATT(Width, "width");
232 SETUP_ATT(Fill, "fill");
233
234 // Setup known format names.
235 #undef SETUP_FMT
236 #define SETUP_FMT(fmt, name) do { \
237 knownFmts.insert(QString::fromLatin1(name), Kuit::Fmt::fmt); \
238 } while (0)
239 SETUP_FMT(Plain, "plain");
240 SETUP_FMT(Rich, "rich");
241 SETUP_FMT(Term, "term");
242
243 // Setup known role names, their default format and subcues.
244 #undef SETUP_ROL
245 #define SETUP_ROL(rol, name, fmt, cues) do { \
246 knownRols.insert(QString::fromLatin1(name), Kuit::Rol::rol); \
247 defFmts[Kuit::Rol::rol][Kuit::Cue::None] = Kuit::Fmt::fmt; \
248 { \
249 using namespace Kuit::Cue; \
250 rolCues[Kuit::Rol::rol] << cues; \
251 } \
252 } while (0)
253 SETUP_ROL(Action, "action", Plain,
254 Button << Inmenu << Intoolbar);
255 SETUP_ROL(Title, "title", Plain,
256 Window << Menu << Tab << Group << Column << Row);
257 SETUP_ROL(Label, "label", Plain,
258 Slider << Spinbox << Listbox << Textbox << Chooser);
259 SETUP_ROL(Option, "option", Plain,
260 Check << Radio);
261 SETUP_ROL(Item, "item", Plain,
262 Inmenu << Inlistbox << Intable << Inrange << Intext);
263 SETUP_ROL(Info, "info", Rich,
264 Tooltip << Whatsthis << Kuit::Cue::Status << Progress
265 << Tipoftheday << Credit << Shell);
266
267 // Setup override formats by subcue.
268 #undef SETUP_ROLCUEFMT
269 #define SETUP_ROLCUEFMT(rol, cue, fmt) do { \
270 defFmts[Kuit::Rol::rol][Kuit::Cue::cue] = Kuit::Fmt::fmt; \
271 } while (0)
272 SETUP_ROLCUEFMT(Info, Status, Plain);
273 SETUP_ROLCUEFMT(Info, Progress, Plain);
274 SETUP_ROLCUEFMT(Info, Credit, Plain);
275 SETUP_ROLCUEFMT(Info, Shell, Term);
276
277 // Setup known subcue names.
278 #undef SETUP_CUE
279 #define SETUP_CUE(cue, name) do { \
280 knownCues.insert(QString::fromLatin1(name), Kuit::Cue::cue); \
281 } while (0)
282 SETUP_CUE(Button, "button");
283 SETUP_CUE(Inmenu, "inmenu");
284 SETUP_CUE(Intoolbar, "intoolbar");
285 SETUP_CUE(Window, "window");
286 SETUP_CUE(Menu, "menu");
287 SETUP_CUE(Tab, "tab");
288 SETUP_CUE(Group, "group");
289 SETUP_CUE(Column, "column");
290 SETUP_CUE(Row, "row");
291 SETUP_CUE(Slider, "slider");
292 SETUP_CUE(Spinbox, "spinbox");
293 SETUP_CUE(Listbox, "listbox");
294 SETUP_CUE(Textbox, "textbox");
295 SETUP_CUE(Chooser, "chooser");
296 SETUP_CUE(Check, "check");
297 SETUP_CUE(Radio, "radio");
298 SETUP_CUE(Inlistbox, "inlistbox");
299 SETUP_CUE(Intable, "intable");
300 SETUP_CUE(Inrange, "inrange");
301 SETUP_CUE(Intext, "intext");
302 SETUP_CUE(Tooltip, "tooltip");
303 SETUP_CUE(Whatsthis, "whatsthis");
304 SETUP_CUE(Status, "status");
305 SETUP_CUE(Progress, "progress");
306 SETUP_CUE(Tipoftheday, "tipoftheday");
307 SETUP_CUE(Credit, "credit");
308 SETUP_CUE(Shell, "shell");
309
310 // Collect all Qt's rich text engine HTML tags, for some checks later.
311 qtHtmlTagNames << QL1S("a") << QL1S("address") << QL1S("b") << QL1S("big") << QL1S("blockquote")
312 << QL1S("body") << QL1S("br") << QL1S("center") << QL1S("cita") << QL1S("code")
313 << QL1S("dd") << QL1S("dfn") << QL1S("div") << QL1S("dl") << QL1S("dt") << QL1S("em")
314 << QL1S("font") << QL1S("h1") << QL1S("h2") << QL1S("h3") << QL1S("h4") << QL1S("h5")
315 << QL1S("h6") << QL1S("head") << QL1S("hr") << QL1S("html") << QL1S("i") << QL1S("img")
316 << QL1S("kbd") << QL1S("meta") << QL1S("li") << QL1S("nobr") << QL1S("ol") << QL1S("p")
317 << QL1S("pre") << QL1S("qt") << QL1S("s") << QL1S("samp") << QL1S("small") << QL1S("span")
318 << QL1S("strong") << QL1S("sup") << QL1S("sub") << QL1S("table") << QL1S("tbody")
319 << QL1S("td") << QL1S("tfoot") << QL1S("th") << QL1S("thead") << QL1S("title")
320 << QL1S("tr") << QL1S("tt") << QL1S("u") << QL1S("ul") << QL1S("var");
321
322 // Tags that format with number of leading newlines.
323 #undef SETUP_TAG_NL
324 #define SETUP_TAG_NL(tag, nlead) do { \
325 leadingNewlines.insert(Kuit::Tag::tag, nlead); \
326 } while (0)
327 SETUP_TAG_NL(Title, 2);
328 SETUP_TAG_NL(Subtitle, 2);
329 SETUP_TAG_NL(Para, 2);
330 SETUP_TAG_NL(List, 1);
331 SETUP_TAG_NL(Bcode, 1);
332 SETUP_TAG_NL(Item, 1);
333
334 // Default XML entities, direct and inverse mapping.
335 xmlEntities[QString::fromLatin1("lt")] = QString(QLatin1Char('<'));
336 xmlEntities[QString::fromLatin1("gt")] = QString(QLatin1Char('>'));
337 xmlEntities[QString::fromLatin1("amp")] = QString(QLatin1Char('&'));
338 xmlEntities[QString::fromLatin1("apos")] = QString(QLatin1Char('\''));
339 xmlEntities[QString::fromLatin1("quot")] = QString(QLatin1Char('"'));
340 xmlEntitiesInverse[QString(QLatin1Char('<'))] = QString::fromLatin1("lt");
341 xmlEntitiesInverse[QString(QLatin1Char('>'))] = QString::fromLatin1("gt");
342 xmlEntitiesInverse[QString(QLatin1Char('&'))] = QString::fromLatin1("amp");
343 xmlEntitiesInverse[QString(QLatin1Char('\''))] = QString::fromLatin1("apos");
344 xmlEntitiesInverse[QString(QLatin1Char('"'))] = QString::fromLatin1("quot");
345 // Custom XML entities.
346 xmlEntities[QString::fromLatin1("nbsp")] = QString(QChar(0xa0));
347 xmlEntityResolver.setEntities(xmlEntities);
348}
349
350K_GLOBAL_STATIC(KuitSemanticsStaticData, semanticsStaticData)
351
352
353// -----------------------------------------------------------------------------
354// The KuitSemanticsPrivate methods, they do the work.
355
356class KuitSemanticsPrivate
357{
358 public:
359
360 KuitSemanticsPrivate (const QString &lang_);
361
362 QString format (const QString &text, const QString &ctxt) const;
363
364 // Get metatranslation (formatting patterns, etc.)
365 QString metaTr (const char *ctxt, const char *id) const;
366
367 // Set visual formatting patterns for text in semantic tags.
368 void setFormattingPatterns ();
369
370 // Set data used in transformation of text within semantic tags.
371 void setTextTransformData ();
372
373 // Compute integer hash key from the set of attributes.
374 static int attSetKey (const QSet<Kuit::AttVar> &aset = QSet<Kuit::AttVar>());
375
376 // Determine visual format by parsing the context marker.
377 static Kuit::FmtVar formatFromContextMarker (const QString &ctxmark,
378 const QString &text);
379 // Determine visual format by parsing tags.
380 static Kuit::FmtVar formatFromTags (const QString &text);
381
382 // Apply appropriate top tag is to the text.
383 static QString equipTopTag (const QString &text, Kuit::TagVar &toptag);
384
385 // Formats the semantic into visual text.
386 QString semanticToVisualText (const QString &text,
387 Kuit::FmtVar fmtExp,
388 Kuit::FmtVar fmtImp) const;
389
390 // Final touches to the formatted text.
391 QString finalizeVisualText (const QString &final,
392 Kuit::FmtVar fmt,
393 bool hadQtTag = false,
394 bool hadAnyHtmlTag = false) const;
395
396 // In case of markup errors, try to make result not look too bad.
397 QString salvageMarkup (const QString &text, Kuit::FmtVar fmt) const;
398
399 // Data for XML parsing state.
400 class OpenEl
401 {
402 public:
403
404 typedef enum { Proper, Ignored, Dropout } Handling;
405
406 Kuit::TagVar tag;
407 QString name;
408 QHash<Kuit::AttVar, QString> avals;
409 int akey;
410 QString astr;
411 Handling handling;
412 QString formattedText;
413 };
414
415 // Gather data about current element for the parse state.
416 KuitSemanticsPrivate::OpenEl parseOpenEl (const QXmlStreamReader &xml,
417 Kuit::TagVar etag,
418 const QString &text) const;
419
420 // Select visual pattern for given tag+attributes+format combination.
421 QString visualPattern (Kuit::TagVar tag, int akey, Kuit::FmtVar fmt) const;
422
423 // Format text of the element.
424 QString formatSubText (const QString &ptext, const OpenEl &oel,
425 Kuit::FmtVar fmt, int numctx) const;
426
427 // Count number of newlines at start and at end of text.
428 static void countWrappingNewlines (const QString &ptext,
429 int &numle, int &numtr);
430
431 // Modifies text for some tags.
432 QString modifyTagText (const QString &text, Kuit::TagVar tag,
433 const QHash<Kuit::AttVar, QString> &avals,
434 int numctx, Kuit::FmtVar fmt) const;
435
436 private:
437
438 QString m_lang;
439
440 QHash<Kuit::TagVar,
441 QHash<int, // attribute set key
442 QHash<Kuit::FmtVar, QString> > > m_patterns;
443
444 QHash<Kuit::FmtVar, QString> m_comboKeyDelim;
445 QHash<Kuit::FmtVar, QString> m_guiPathDelim;
446
447 QHash<QString, QString> m_keyNames;
448
449 // For fetching metatranslations.
450 KCatalog *m_metaCat;
451};
452
453KuitSemanticsPrivate::KuitSemanticsPrivate (const QString &lang)
454: m_metaCat(NULL)
455{
456 m_lang = lang;
457
458 // NOTE: This function draws translation from raw message catalogs
459 // because full i18n system is not available at this point (this
460 // function is called within the initialization of the i18n system),
461 // Also, pattern/transformation strings are "metastrings", not
462 // fully proper i18n strings on their own.
463
464 m_metaCat = new KCatalog(QString::fromLatin1("kdelibs4"), lang);
465
466 // Get formatting patterns for all tag/att/fmt combinations.
467 setFormattingPatterns();
468
469 // Get data for tag text transformations.
470 setTextTransformData();
471
472 // Catalog not needed any more.
473 delete m_metaCat;
474 m_metaCat = NULL;
475}
476
477QString KuitSemanticsPrivate::metaTr (const char *ctxt, const char *id) const
478{
479 if (m_metaCat == NULL) {
480 return QString::fromLatin1(id);
481 }
482 return m_metaCat->translate(ctxt, id);
483}
484
485void KuitSemanticsPrivate::setFormattingPatterns ()
486{
487 using namespace Kuit;
488
489 // Macro to expedite setting the patterns.
490 #undef SET_PATTERN
491 #define SET_PATTERN(tag, atts, fmt, ctxt_ptrn) do { \
492 QSet<AttVar> aset; \
493 aset << atts; \
494 int akey = attSetKey(aset); \
495 QString pattern = metaTr(ctxt_ptrn); \
496 m_patterns[tag][akey][fmt] = pattern; \
497 /* Make Term pattern same as Plain, unless explicitly given. */ \
498 if (fmt == Fmt::Plain && !m_patterns[tag][akey].contains(Fmt::Term)) { \
499 m_patterns[tag][akey][Fmt::Term] = pattern; \
500 } \
501 } while (0)
502
503 // Normal I18N_NOOP2 removes context, but below we need both.
504 #undef I18N_NOOP2
505 #define I18N_NOOP2(ctxt, msg) ctxt, msg
506
507 // Some of the formatting patterns are intentionally not exposed for
508 // localization.
509 #undef XXXX_NOOP2
510 #define XXXX_NOOP2(ctxt, msg) ctxt, msg
511
512 // NOTE: The following "i18n:" comments are oddly placed in order that
513 // xgettext extracts them properly.
514
515 // -------> Title
516 SET_PATTERN(Tag::Title, Att::None, Fmt::Plain,
517 I18N_NOOP2("@title/plain",
518 // i18n: The following messages, with msgctxt "@tag/modifier",
519 // are KUIT patterns for formatting the text found inside semantic tags.
520 // For review of the KUIT semantic markup, see the article on Techbase:
521 // http://techbase.kde.org/Development/Tutorials/Localization/i18n_Semantics
522 // The "/modifier" tells if the pattern is used for plain text, or rich text
523 // which can use HTML tags.
524 // You may be in general satisfied with the patterns as they are in the
525 // original. Some things you may think about changing:
526 // - the proper quotes, those used in msgid are English-standard
527 // - the <i> and <b> tags, does your language script work well with them?
528 "== %1 =="));
529 SET_PATTERN(Tag::Title, Att::None, Fmt::Rich,
530 I18N_NOOP2("@title/rich",
531 // i18n: KUIT pattern, see the comment to the first of these entries above.
532 "<h2>%1</h2>"));
533
534 // -------> Subtitle
535 SET_PATTERN(Tag::Subtitle, Att::None, Fmt::Plain,
536 I18N_NOOP2("@subtitle/plain",
537 // i18n: KUIT pattern, see the comment to the first of these entries above.
538 "~ %1 ~"));
539 SET_PATTERN(Tag::Subtitle, Att::None, Fmt::Rich,
540 I18N_NOOP2("@subtitle/rich",
541 // i18n: KUIT pattern, see the comment to the first of these entries above.
542 "<h3>%1</h3>"));
543
544 // -------> Para
545 SET_PATTERN(Tag::Para, Att::None, Fmt::Plain,
546 XXXX_NOOP2("@para/plain",
547 // i18n: KUIT pattern, see the comment to the first of these entries above.
548 "%1"));
549 SET_PATTERN(Tag::Para, Att::None, Fmt::Rich,
550 XXXX_NOOP2("@para/rich",
551 // i18n: KUIT pattern, see the comment to the first of these entries above.
552 "<p>%1</p>"));
553
554 // -------> List
555 SET_PATTERN(Tag::List, Att::None, Fmt::Plain,
556 XXXX_NOOP2("@list/plain",
557 // i18n: KUIT pattern, see the comment to the first of these entries above.
558 "%1"));
559 SET_PATTERN(Tag::List, Att::None, Fmt::Rich,
560 XXXX_NOOP2("@list/rich",
561 // i18n: KUIT pattern, see the comment to the first of these entries above.
562 "<ul>%1</ul>"));
563
564 // -------> Item
565 SET_PATTERN(Tag::Item, Att::None, Fmt::Plain,
566 I18N_NOOP2("@item/plain",
567 // i18n: KUIT pattern, see the comment to the first of these entries above.
568 " * %1"));
569 SET_PATTERN(Tag::Item, Att::None, Fmt::Rich,
570 I18N_NOOP2("@item/rich",
571 // i18n: KUIT pattern, see the comment to the first of these entries above.
572 "<li>%1</li>"));
573
574 // -------> Note
575 SET_PATTERN(Tag::Note, Att::None, Fmt::Plain,
576 I18N_NOOP2("@note/plain",
577 // i18n: KUIT pattern, see the comment to the first of these entries above.
578 "Note: %1"));
579 SET_PATTERN(Tag::Note, Att::None, Fmt::Rich,
580 I18N_NOOP2("@note/rich",
581 // i18n: KUIT pattern, see the comment to the first of these entries above.
582 "<i>Note</i>: %1"));
583 SET_PATTERN(Tag::Note, Att::Label, Fmt::Plain,
584 I18N_NOOP2("@note-with-label/plain\n"
585 "%1 is the note label, %2 is the text",
586 // i18n: KUIT pattern, see the comment to the first of these entries above.
587 "%1: %2"));
588 SET_PATTERN(Tag::Note, Att::Label, Fmt::Rich,
589 I18N_NOOP2("@note-with-label/rich\n"
590 "%1 is the note label, %2 is the text",
591 // i18n: KUIT pattern, see the comment to the first of these entries above.
592 "<i>%1</i>: %2"));
593
594 // -------> Warning
595 SET_PATTERN(Tag::Warning, Att::None, Fmt::Plain,
596 I18N_NOOP2("@warning/plain",
597 // i18n: KUIT pattern, see the comment to the first of these entries above.
598 "WARNING: %1"));
599 SET_PATTERN(Tag::Warning, Att::None, Fmt::Rich,
600 I18N_NOOP2("@warning/rich",
601 // i18n: KUIT pattern, see the comment to the first of these entries above.
602 "<b>Warning</b>: %1"));
603 SET_PATTERN(Tag::Warning, Att::Label, Fmt::Plain,
604 I18N_NOOP2("@warning-with-label/plain\n"
605 "%1 is the warning label, %2 is the text",
606 // i18n: KUIT pattern, see the comment to the first of these entries above.
607 "%1: %2"));
608 SET_PATTERN(Tag::Warning, Att::Label, Fmt::Rich,
609 I18N_NOOP2("@warning-with-label/rich\n"
610 "%1 is the warning label, %2 is the text",
611 // i18n: KUIT pattern, see the comment to the first of these entries above.
612 "<b>%1</b>: %2"));
613
614 // -------> Link
615 SET_PATTERN(Tag::Link, Att::None, Fmt::Plain,
616 XXXX_NOOP2("@link/plain",
617 // i18n: KUIT pattern, see the comment to the first of these entries above.
618 "%1"));
619 SET_PATTERN(Tag::Link, Att::None, Fmt::Rich,
620 XXXX_NOOP2("@link/rich",
621 // i18n: KUIT pattern, see the comment to the first of these entries above.
622 "<a href=\"%1\">%1</a>"));
623 SET_PATTERN(Tag::Link, Att::Url, Fmt::Plain,
624 I18N_NOOP2("@link-with-description/plain\n"
625 "%1 is the URL, %2 is the descriptive text",
626 // i18n: KUIT pattern, see the comment to the first of these entries above.
627 "%2 (%1)"));
628 SET_PATTERN(Tag::Link, Att::Url, Fmt::Rich,
629 I18N_NOOP2("@link-with-description/rich\n"
630 "%1 is the URL, %2 is the descriptive text",
631 // i18n: KUIT pattern, see the comment to the first of these entries above.
632 "<a href=\"%1\">%2</a>"));
633
634 // -------> Filename
635 SET_PATTERN(Tag::Filename, Att::None, Fmt::Plain,
636 I18N_NOOP2("@filename/plain",
637 // i18n: KUIT pattern, see the comment to the first of these entries above.
638 "‘%1’"));
639 SET_PATTERN(Tag::Filename, Att::None, Fmt::Rich,
640 I18N_NOOP2("@filename/rich",
641 // i18n: KUIT pattern, see the comment to the first of these entries above.
642 "<tt>%1</tt>"));
643
644 // -------> Application
645 SET_PATTERN(Tag::Application, Att::None, Fmt::Plain,
646 I18N_NOOP2("@application/plain",
647 // i18n: KUIT pattern, see the comment to the first of these entries above.
648 "%1"));
649 SET_PATTERN(Tag::Application, Att::None, Fmt::Rich,
650 I18N_NOOP2("@application/rich",
651 // i18n: KUIT pattern, see the comment to the first of these entries above.
652 "%1"));
653
654 // -------> Command
655 SET_PATTERN(Tag::Command, Att::None, Fmt::Plain,
656 I18N_NOOP2("@command/plain",
657 // i18n: KUIT pattern, see the comment to the first of these entries above.
658 "%1"));
659 SET_PATTERN(Tag::Command, Att::None, Fmt::Rich,
660 I18N_NOOP2("@command/rich",
661 // i18n: KUIT pattern, see the comment to the first of these entries above.
662 "<tt>%1</tt>"));
663 SET_PATTERN(Tag::Command, Att::Section, Fmt::Plain,
664 I18N_NOOP2("@command-with-section/plain\n"
665 "%1 is the command name, %2 is its man section",
666 // i18n: KUIT pattern, see the comment to the first of these entries above.
667 "%1(%2)"));
668 SET_PATTERN(Tag::Command, Att::Section, Fmt::Rich,
669 I18N_NOOP2("@command-with-section/rich\n"
670 "%1 is the command name, %2 is its man section",
671 // i18n: KUIT pattern, see the comment to the first of these entries above.
672 "<tt>%1(%2)</tt>"));
673
674 // -------> Resource
675 SET_PATTERN(Tag::Resource, Att::None, Fmt::Plain,
676 I18N_NOOP2("@resource/plain",
677 // i18n: KUIT pattern, see the comment to the first of these entries above.
678 "“%1”"));
679 SET_PATTERN(Tag::Resource, Att::None, Fmt::Rich,
680 I18N_NOOP2("@resource/rich",
681 // i18n: KUIT pattern, see the comment to the first of these entries above.
682 "“%1”"));
683
684 // -------> Icode
685 SET_PATTERN(Tag::Icode, Att::None, Fmt::Plain,
686 I18N_NOOP2("@icode/plain",
687 // i18n: KUIT pattern, see the comment to the first of these entries above.
688 "“%1”"));
689 SET_PATTERN(Tag::Icode, Att::None, Fmt::Rich,
690 I18N_NOOP2("@icode/rich",
691 // i18n: KUIT pattern, see the comment to the first of these entries above.
692 "<tt>%1</tt>"));
693
694 // -------> Bcode
695 SET_PATTERN(Tag::Bcode, Att::None, Fmt::Plain,
696 XXXX_NOOP2("@bcode/plain",
697 // i18n: KUIT pattern, see the comment to the first of these entries above.
698 "\n%1\n"));
699 SET_PATTERN(Tag::Bcode, Att::None, Fmt::Rich,
700 XXXX_NOOP2("@bcode/rich",
701 // i18n: KUIT pattern, see the comment to the first of these entries above.
702 "<pre>%1</pre>"));
703
704 // -------> Shortcut
705 SET_PATTERN(Tag::Shortcut, Att::None, Fmt::Plain,
706 I18N_NOOP2("@shortcut/plain",
707 // i18n: KUIT pattern, see the comment to the first of these entries above.
708 "%1"));
709 SET_PATTERN(Tag::Shortcut, Att::None, Fmt::Rich,
710 I18N_NOOP2("@shortcut/rich",
711 // i18n: KUIT pattern, see the comment to the first of these entries above.
712 "<b>%1</b>"));
713
714 // -------> Interface
715 SET_PATTERN(Tag::Interface, Att::None, Fmt::Plain,
716 I18N_NOOP2("@interface/plain",
717 // i18n: KUIT pattern, see the comment to the first of these entries above.
718 "|%1|"));
719 SET_PATTERN(Tag::Interface, Att::None, Fmt::Rich,
720 I18N_NOOP2("@interface/rich",
721 // i18n: KUIT pattern, see the comment to the first of these entries above.
722 "<i>%1</i>"));
723
724 // -------> Emphasis
725 SET_PATTERN(Tag::Emphasis, Att::None, Fmt::Plain,
726 I18N_NOOP2("@emphasis/plain",
727 // i18n: KUIT pattern, see the comment to the first of these entries above.
728 "*%1*"));
729 SET_PATTERN(Tag::Emphasis, Att::None, Fmt::Rich,
730 I18N_NOOP2("@emphasis/rich",
731 // i18n: KUIT pattern, see the comment to the first of these entries above.
732 "<i>%1</i>"));
733 SET_PATTERN(Tag::Emphasis, Att::Strong, Fmt::Plain,
734 I18N_NOOP2("@emphasis-strong/plain",
735 // i18n: KUIT pattern, see the comment to the first of these entries above.
736 "**%1**"));
737 SET_PATTERN(Tag::Emphasis, Att::Strong, Fmt::Rich,
738 I18N_NOOP2("@emphasis-strong/rich",
739 // i18n: KUIT pattern, see the comment to the first of these entries above.
740 "<b>%1</b>"));
741
742 // -------> Placeholder
743 SET_PATTERN(Tag::Placeholder, Att::None, Fmt::Plain,
744 I18N_NOOP2("@placeholder/plain",
745 // i18n: KUIT pattern, see the comment to the first of these entries above.
746 "&lt;%1&gt;"));
747 SET_PATTERN(Tag::Placeholder, Att::None, Fmt::Rich,
748 I18N_NOOP2("@placeholder/rich",
749 // i18n: KUIT pattern, see the comment to the first of these entries above.
750 "&lt;<i>%1</i>&gt;"));
751
752 // -------> Email
753 SET_PATTERN(Tag::Email, Att::None, Fmt::Plain,
754 I18N_NOOP2("@email/plain",
755 // i18n: KUIT pattern, see the comment to the first of these entries above.
756 "&lt;%1&gt;"));
757 SET_PATTERN(Tag::Email, Att::None, Fmt::Rich,
758 I18N_NOOP2("@email/rich",
759 // i18n: KUIT pattern, see the comment to the first of these entries above.
760 "&lt;<a href=\"mailto:%1\">%1</a>&gt;"));
761 SET_PATTERN(Tag::Email, Att::Address, Fmt::Plain,
762 I18N_NOOP2("@email-with-name/plain\n"
763 "%1 is name, %2 is address",
764 // i18n: KUIT pattern, see the comment to the first of these entries above.
765 "%1 &lt;%2&gt;"));
766 SET_PATTERN(Tag::Email, Att::Address, Fmt::Rich,
767 I18N_NOOP2("@email-with-name/rich\n"
768 "%1 is name, %2 is address",
769 // i18n: KUIT pattern, see the comment to the first of these entries above.
770 "<a href=\"mailto:%2\">%1</a>"));
771
772 // -------> Envar
773 SET_PATTERN(Tag::Envar, Att::None, Fmt::Plain,
774 I18N_NOOP2("@envar/plain",
775 // i18n: KUIT pattern, see the comment to the first of these entries above.
776 "$%1"));
777 SET_PATTERN(Tag::Envar, Att::None, Fmt::Rich,
778 I18N_NOOP2("@envar/rich",
779 // i18n: KUIT pattern, see the comment to the first of these entries above.
780 "<tt>$%1</tt>"));
781
782 // -------> Message
783 SET_PATTERN(Tag::Message, Att::None, Fmt::Plain,
784 I18N_NOOP2("@message/plain",
785 // i18n: KUIT pattern, see the comment to the first of these entries above.
786 "/%1/"));
787 SET_PATTERN(Tag::Message, Att::None, Fmt::Rich,
788 I18N_NOOP2("@message/rich",
789 // i18n: KUIT pattern, see the comment to the first of these entries above.
790 "<i>%1</i>"));
791
792 // -------> Nl
793 SET_PATTERN(Tag::Nl, Att::None, Fmt::Plain,
794 XXXX_NOOP2("@nl/plain",
795 // i18n: KUIT pattern, see the comment to the first of these entries above.
796 "%1\n"));
797 SET_PATTERN(Tag::Nl, Att::None, Fmt::Rich,
798 XXXX_NOOP2("@nl/rich",
799 // i18n: KUIT pattern, see the comment to the first of these entries above.
800 "%1<br/>"));
801}
802
803void KuitSemanticsPrivate::setTextTransformData ()
804{
805 // Mask metaTr with I18N_NOOP2 to have stuff extracted.
806 #undef I18N_NOOP2
807 #define I18N_NOOP2(ctxt, msg) metaTr(ctxt, msg)
808
809 // i18n: Decide which string is used to delimit keys in a keyboard
810 // shortcut (e.g. + in Ctrl+Alt+Tab) in plain text.
811 m_comboKeyDelim[Kuit::Fmt::Plain] = I18N_NOOP2("shortcut-key-delimiter/plain", "+");
812 m_comboKeyDelim[Kuit::Fmt::Term] = m_comboKeyDelim[Kuit::Fmt::Plain];
813 // i18n: Decide which string is used to delimit keys in a keyboard
814 // shortcut (e.g. + in Ctrl+Alt+Tab) in rich text.
815 m_comboKeyDelim[Kuit::Fmt::Rich] = I18N_NOOP2("shortcut-key-delimiter/rich", "+");
816
817 // i18n: Decide which string is used to delimit elements in a GUI path
818 // (e.g. -> in "Go to Settings->Advanced->Core tab.") in plain text.
819 m_guiPathDelim[Kuit::Fmt::Plain] = I18N_NOOP2("gui-path-delimiter/plain", "→");
820 m_guiPathDelim[Kuit::Fmt::Term] = m_guiPathDelim[Kuit::Fmt::Plain];
821 // i18n: Decide which string is used to delimit elements in a GUI path
822 // (e.g. -> in "Go to Settings->Advanced->Core tab.") in rich text.
823 m_guiPathDelim[Kuit::Fmt::Rich] = I18N_NOOP2("gui-path-delimiter/rich", "→");
824 // NOTE: The '→' glyph seems to be available in all widespread fonts.
825
826 // Collect keyboard key names.
827 #undef SET_KEYNAME
828 #define SET_KEYNAME(rawname) do { \
829 /* Normalize key, trim and all lower-case. */ \
830 QString normname = QString::fromLatin1(rawname).trimmed().toLower(); \
831 m_keyNames[normname] = metaTr("keyboard-key-name", rawname); \
832 } while (0)
833
834 // Now we need I18N_NOOP2 that does remove context.
835 #undef I18N_NOOP2
836 #define I18N_NOOP2(ctxt, msg) msg
837
838 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Alt"));
839 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "AltGr"));
840 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Backspace"));
841 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "CapsLock"));
842 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Control"));
843 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Ctrl"));
844 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Del"));
845 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Delete"));
846 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Down"));
847 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "End"));
848 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Enter"));
849 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Esc"));
850 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Escape"));
851 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Home"));
852 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Hyper"));
853 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Ins"));
854 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Insert"));
855 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Left"));
856 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Menu"));
857 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Meta"));
858 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "NumLock"));
859 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "PageDown"));
860 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "PageUp"));
861 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "PgDown"));
862 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "PgUp"));
863 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "PauseBreak"));
864 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "PrintScreen"));
865 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "PrtScr"));
866 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Return"));
867 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Right"));
868 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "ScrollLock"));
869 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Shift"));
870 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Space"));
871 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Super"));
872 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "SysReq"));
873 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Tab"));
874 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Up"));
875 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "Win"));
876 // TODO: Add rest of the key names?
877
878 // i18n: Pattern for the function keys.
879 SET_KEYNAME(I18N_NOOP2("keyboard-key-name", "F%1"));
880}
881
882QString KuitSemanticsPrivate::format (const QString &text,
883 const QString &ctxt) const
884{
885 // Parse context marker to determine format.
886 Kuit::FmtVar fmtExplicit = formatFromContextMarker(ctxt, text);
887
888 // Quick check: are there any tags at all?
889 if (text.indexOf(QLatin1Char('<')) < 0) {
890 return finalizeVisualText(text, fmtExplicit);
891 }
892
893 // If format not explicitly given, heuristically determine
894 // implicit format based on presence or lack of HTML tags.
895 Kuit::FmtVar fmtImplicit = fmtExplicit;
896 if (fmtExplicit == Kuit::Fmt::None) {
897 fmtImplicit = formatFromTags(text);
898 }
899
900 // Decide on the top tag, either TopLong or TopShort,
901 // and wrap the text with it.
902 Kuit::TagVar toptag;
903 QString wtext = equipTopTag(text, toptag);
904
905 // Format the text.
906 QString ftext = semanticToVisualText(wtext, fmtExplicit, fmtImplicit);
907 if (ftext.isEmpty()) { // error while processing markup
908 return salvageMarkup(text, fmtImplicit);
909 }
910
911 return ftext;
912}
913
914int KuitSemanticsPrivate::attSetKey (const QSet<Kuit::AttVar> &aset)
915{
916 QList<Kuit::AttVar> alist = aset.toList();
917 qSort(alist);
918 int key = 0;
919 int tenp = 1;
920 foreach (const Kuit::AttVar &att, alist) {
921 key += att * tenp;
922 tenp *= 10;
923 }
924 return key;
925}
926
927Kuit::FmtVar KuitSemanticsPrivate::formatFromContextMarker (
928 const QString &ctxmark_, const QString &text)
929{
930 #ifdef NDEBUG
931 Q_UNUSED(text);
932 #endif
933
934 KuitSemanticsStaticData *s = semanticsStaticData;
935
936 // Semantic context marker is in the form @rolname:cuename/fmtname,
937 // and must start just after any leading whitespace in the context string.
938 QString rolname;
939 QString fmtname;
940 QString cuename;
941 QString ctxmark = ctxmark_.trimmed();
942 if (ctxmark.startsWith(QLatin1Char('@'))) { // found context marker
943 static QRegExp wsRx(QString::fromLatin1("\\s"));
944 ctxmark = ctxmark.mid(1, wsRx.indexIn(ctxmark) - 1);
945
946 // Possible visual format.
947 int pfmt = ctxmark.indexOf(QLatin1Char('/'));
948 if (pfmt >= 0) {
949 fmtname = ctxmark.mid(pfmt + 1);
950 ctxmark = ctxmark.left(pfmt);
951 }
952
953 // Possible interface subcue.
954 int pcue = ctxmark.indexOf(QLatin1Char(':'));
955 if (pcue >= 0) {
956 cuename = ctxmark.mid(pcue + 1);
957 ctxmark = ctxmark.left(pcue);
958 }
959
960 // Semantic role.
961 rolname = ctxmark;
962 }
963 // Names remain empty if marker was not found, which is ok.
964
965 // Normalize names.
966 rolname = rolname.trimmed().toLower();
967 cuename = cuename.trimmed().toLower();
968 fmtname = fmtname.trimmed().toLower();
969
970 // Set role from name.
971 Kuit::RolVar rol;
972 if (s->knownRols.contains(rolname)) { // known role
973 rol = s->knownRols[rolname];
974 }
975 else { // unknown role
976 rol = Kuit::Rol::None;
977 if (!rolname.isEmpty()) {
978 kDebug(173) << QString::fromLatin1("Unknown semantic role '@%1' in "
979 "context marker for message {%2}.")
980 .arg(rolname, shorten(text));
981 }
982 }
983
984 // Set subcue from name.
985 Kuit::CueVar cue;
986 if (s->knownCues.contains(cuename)) { // known subcue
987 cue = s->knownCues[cuename];
988 }
989 else { // unknown or not given subcue
990 cue = Kuit::Cue::None;
991 if (!cuename.isEmpty()) {
992 kDebug(173) << QString::fromLatin1("Unknown interface subcue ':%1' in "
993 "context marker for message {%2}.")
994 .arg(cuename, shorten(text));
995 }
996 }
997
998 // Set format from name, or by derivation from contex/subcue.
999 Kuit::FmtVar fmt;
1000 if (s->knownFmts.contains(fmtname)) { // known format
1001 fmt = s->knownFmts[fmtname];
1002 }
1003 else { // unknown or not given format
1004
1005 // Check first if there is a format defined for role/subcue
1006 // combination, than for role only, then default to none.
1007 if (s->defFmts.contains(rol)) {
1008 if (s->defFmts[rol].contains(cue)) {
1009 fmt = s->defFmts[rol][cue];
1010 }
1011 else {
1012 fmt = s->defFmts[rol][Kuit::Cue::None];
1013 }
1014 }
1015 else {
1016 fmt = Kuit::Fmt::None;
1017 }
1018
1019 if (!fmtname.isEmpty()) {
1020 kDebug(173) << QString::fromLatin1("Unknown visual format '/%1' in "
1021 "context marker for message {%2}.")
1022 .arg(fmtname, shorten(text));
1023 }
1024 }
1025
1026 return fmt;
1027}
1028
1029Kuit::FmtVar KuitSemanticsPrivate::formatFromTags (const QString &text)
1030{
1031 KuitSemanticsStaticData *s = semanticsStaticData;
1032 static QRegExp staticTagRx(QString::fromLatin1("<\\s*(\\w+)[^>]*>"));
1033
1034 QRegExp tagRx = staticTagRx; // for thread-safety
1035 int p = tagRx.indexIn(text);
1036 while (p >= 0) {
1037 QString tagname = tagRx.capturedTexts().at(1).toLower();
1038 if (s->qtHtmlTagNames.contains(tagname)) {
1039 return Kuit::Fmt::Rich;
1040 }
1041 p = tagRx.indexIn(text, p + tagRx.matchedLength());
1042 }
1043 return Kuit::Fmt::Plain;
1044}
1045
1046QString KuitSemanticsPrivate::equipTopTag (const QString &text_,
1047 Kuit::TagVar &toptag)
1048{
1049 KuitSemanticsStaticData *s = semanticsStaticData;
1050
1051 // Unless the text opens either with TopLong or TopShort tags,
1052 // make a guess: if it opens with one of Title, Subtitle, Para,
1053 // consider it TopLong, otherwise TopShort.
1054 static QRegExp opensWithTagRx(QString::fromLatin1("^\\s*<\\s*(\\w+)[^>]*>"));
1055 bool explicitTopTag = false;
1056
1057 QString text = text_;
1058 int p = opensWithTagRx.indexIn(text);
1059
1060 // <qt> or <html> tag are to be ignored for deciding the top tag.
1061 if (p >= 0) {
1062 QString fullmatch = opensWithTagRx.capturedTexts().at(0);
1063 QString tagname = opensWithTagRx.capturedTexts().at(1).toLower();
1064 if (tagname == QLatin1String("qt") || tagname == QLatin1String("html")) {
1065 // Kill the tag and see if there is another one following,
1066 // for primary check below.
1067 text = text.mid(fullmatch.length());
1068 p = opensWithTagRx.indexIn(text);
1069 }
1070 }
1071
1072 // Check the first non-<qt>/<html> tag.
1073 if (p >= 0) { // opens with a tag
1074 QString tagname = opensWithTagRx.capturedTexts().at(1).toLower();
1075 if (s->knownTags.contains(tagname)) { // a known tag
1076 Kuit::TagVar tag = s->knownTags[tagname];
1077 if ( tag == Kuit::Tag::TopLong
1078 || tag == Kuit::Tag::TopShort) { // explicitly given top tag
1079 toptag = tag;
1080 explicitTopTag = true;
1081 }
1082 else if ( tag == Kuit::Tag::Para
1083 || tag == Kuit::Tag::Title
1084 || tag == Kuit::Tag::Subtitle) { // one of long text tags
1085 toptag = Kuit::Tag::TopLong;
1086 }
1087 else { // not one of long text tags
1088 toptag = Kuit::Tag::TopShort;
1089 }
1090 }
1091 else { // not a KUIT tag
1092 toptag = Kuit::Tag::TopShort;
1093 }
1094 }
1095 else { // doesn't open with a tag
1096 toptag = Kuit::Tag::TopShort;
1097 }
1098
1099 // Wrap text with top tag if not explicitly given.
1100 if (!explicitTopTag) {
1101 return QLatin1Char('<') + s->tagNames[toptag] + QLatin1Char('>')
1102 + text_ // original text, not the one possibly stripped above
1103 + QLatin1String("</") + s->tagNames[toptag] + QLatin1Char('>');
1104 }
1105 else {
1106 return text;
1107 }
1108}
1109
1110#define ENTITY_SUBRX "[a-z]+|#[0-9]+|#x[0-9a-fA-F]+"
1111
1112QString KuitSemanticsPrivate::semanticToVisualText (const QString &text_,
1113 Kuit::FmtVar fmtExp_,
1114 Kuit::FmtVar fmtImp_) const
1115{
1116 KuitSemanticsStaticData *s = semanticsStaticData;
1117
1118 // Replace &-shortcut marker with "&amp;", not to confuse the parser;
1119 // but do not touch & which forms an XML entity as it is.
1120 QString original = text_;
1121 QString text;
1122 int p = original.indexOf(QLatin1Char('&'));
1123 while (p >= 0) {
1124 text.append(original.mid(0, p + 1));
1125 original.remove(0, p + 1);
1126 static QRegExp restRx(QString::fromLatin1("^(" ENTITY_SUBRX ");"));
1127 if (original.indexOf(restRx) != 0) { // not an entity
1128 text.append(QLatin1String("amp;"));
1129 }
1130 p = original.indexOf(QLatin1Char('&'));
1131 }
1132 text.append(original);
1133
1134 Kuit::FmtVar fmtExp = fmtExp_;
1135 Kuit::FmtVar fmtImp = fmtImp_;
1136 int numCtx = 0;
1137 bool hadQtTag = false;
1138 bool hadAnyHtmlTag = false;
1139 QStack<OpenEl> openEls;
1140 QXmlStreamReader xml(text);
1141 xml.setEntityResolver(&s->xmlEntityResolver);
1142 QStringRef lastElementName;
1143
1144 while (!xml.atEnd()) {
1145 xml.readNext();
1146
1147 if (xml.isStartElement()) {
1148 lastElementName = xml.name();
1149
1150 // Find first proper enclosing element tag.
1151 Kuit::TagVar etag = Kuit::Tag::None;
1152 for (int i = openEls.size() - 1; i >= 0; --i) {
1153 if (openEls[i].handling == OpenEl::Proper) {
1154 etag = openEls[i].tag;
1155 break;
1156 }
1157 }
1158
1159 // Collect data about this element.
1160 OpenEl oel = parseOpenEl(xml, etag, text);
1161 if (oel.name == QLatin1String("qt") || oel.name == QLatin1String("html")) {
1162 hadQtTag = true;
1163 }
1164 if (s->qtHtmlTagNames.contains(oel.name)) {
1165 hadAnyHtmlTag = true;
1166 }
1167
1168 // If this is top tag, check if it overrides the context marker
1169 // by its ctx attribute.
1170 if (openEls.isEmpty() && oel.avals.contains(Kuit::Att::Ctx)) {
1171 // Resolve format override.
1172 fmtExp = formatFromContextMarker(oel.avals[Kuit::Att::Ctx], text);
1173 fmtImp = fmtExp;
1174 }
1175
1176 // Record the new element on the parse stack.
1177 openEls.push(oel);
1178
1179 // Update numeric context.
1180 if (oel.tag == Kuit::Tag::Numid) {
1181 ++numCtx;
1182 }
1183 }
1184 else if (xml.isEndElement()) {
1185 // Get closed element data.
1186 OpenEl oel = openEls.pop();
1187
1188 // If this was closing of the top element, we're done.
1189 if (openEls.isEmpty()) {
1190 // Return with final touches applied.
1191 return finalizeVisualText(oel.formattedText, fmtExp,
1192 hadQtTag, hadAnyHtmlTag);
1193 }
1194
1195 // Append formatted text segment.
1196 QString pt = openEls.top().formattedText; // preceding text
1197 openEls.top().formattedText += formatSubText(pt, oel, fmtImp, numCtx);
1198
1199 // Update numeric context.
1200 if (oel.tag == Kuit::Tag::Numid) {
1201 --numCtx;
1202 }
1203 }
1204 else if (xml.isCharacters()) {
1205 // Stream reader will automatically resolve default XML entities,
1206 // which is not desired in this case, as the final text may
1207 // be rich. Convert them back into entities.
1208 QString text = xml.text().toString();
1209 QString ntext;
1210 foreach (const QChar &c, text) {
1211 if (s->xmlEntitiesInverse.contains(c)) {
1212 const QString entname = s->xmlEntitiesInverse[c];
1213 ntext += QLatin1Char('&') + entname + QLatin1Char(';');
1214 } else {
1215 ntext += c;
1216 }
1217 }
1218 openEls.top().formattedText += ntext;
1219 }
1220 }
1221
1222 if (xml.hasError()) {
1223 kDebug(173) << QString::fromLatin1("Markup error in message {%1}: %2. Last tag parsed: %3")
1224 .arg(shorten(text), xml.errorString(), lastElementName.toString());
1225 return QString();
1226 }
1227
1228 // Cannot reach here.
1229 return text;
1230}
1231
1232KuitSemanticsPrivate::OpenEl
1233KuitSemanticsPrivate::parseOpenEl (const QXmlStreamReader &xml,
1234 Kuit::TagVar etag,
1235 const QString &text) const
1236{
1237 #ifdef NDEBUG
1238 Q_UNUSED(text);
1239 #endif
1240
1241 KuitSemanticsStaticData *s = semanticsStaticData;
1242
1243 OpenEl oel;
1244 oel.name = xml.name().toString().toLower();
1245
1246 // Collect attribute names and values, and format attribute string.
1247 QStringList attnams, attvals;
1248 foreach (const QXmlStreamAttribute &xatt, xml.attributes()) {
1249 attnams += xatt.name().toString().toLower();
1250 attvals += xatt.value().toString();
1251 QChar qc = attvals.last().indexOf(QLatin1Char('\'')) < 0 ? QLatin1Char('\'') : QLatin1Char('"');
1252 oel.astr += QLatin1Char(' ') + attnams.last() + QLatin1Char('=') + qc + attvals.last() + qc;
1253 }
1254
1255 if (s->knownTags.contains(oel.name)) { // known KUIT element
1256 oel.tag = s->knownTags[oel.name];
1257
1258 // If this element can be contained within enclosing element,
1259 // mark it proper, otherwise mark it for removal.
1260 if (etag == Kuit::Tag::None || s->tagSubs[etag].contains(oel.tag)) {
1261 oel.handling = OpenEl::Proper;
1262 }
1263 else {
1264 oel.handling = OpenEl::Dropout;
1265 kDebug(173) << QString::fromLatin1("Tag '%1' cannot be subtag of '%2' "
1266 "in message {%3}.")
1267 .arg(s->tagNames[oel.tag], s->tagNames[etag],
1268 shorten(text));
1269 }
1270
1271 // Resolve attributes and compute attribute set key.
1272 QSet<Kuit::AttVar> attset;
1273 for (int i = 0; i < attnams.size(); ++i) {
1274 if (s->knownAtts.contains(attnams[i])) {
1275 Kuit::AttVar att = s->knownAtts[attnams[i]];
1276 if (s->tagAtts[oel.tag].contains(att)) {
1277 attset << att;
1278 oel.avals[att] = attvals[i];
1279 }
1280 else {
1281 kDebug(173) << QString::fromLatin1("Attribute '%1' cannot be used in "
1282 "tag '%2' in message {%3}.")
1283 .arg(attnams[i], oel.name,
1284 shorten(text));
1285 }
1286 }
1287 else {
1288 kDebug(173) << QString::fromLatin1("Unknown semantic tag attribute '%1' "
1289 "in message {%2}.")
1290 .arg(attnams[i], shorten(text));
1291 }
1292 }
1293 oel.akey = attSetKey(attset);
1294 }
1295 else if (oel.name == QLatin1String("qt") || oel.name == QLatin1String("html")) {
1296 // Drop qt/html tags (gets added in the end).
1297 oel.handling = OpenEl::Dropout;
1298 }
1299 else { // other element, leave it in verbatim
1300 oel.handling = OpenEl::Ignored;
1301 if (!s->qtHtmlTagNames.contains(oel.name)) {
1302 kDebug(173) << QString::fromLatin1("Tag '%1' is neither semantic nor HTML in "
1303 "message {%3}.")
1304 .arg(oel.name, shorten(text));
1305 }
1306 }
1307
1308 return oel;
1309}
1310
1311QString KuitSemanticsPrivate::visualPattern (Kuit::TagVar tag, int akey,
1312 Kuit::FmtVar fmt) const
1313{
1314 // Default pattern: simple substitution.
1315 QString pattern = QString::fromLatin1("%1");
1316
1317 // See if there is a pattern specifically for this element.
1318 if ( m_patterns.contains(tag)
1319 && m_patterns[tag].contains(akey)
1320 && m_patterns[tag][akey].contains(fmt))
1321 {
1322 pattern = m_patterns[tag][akey][fmt];
1323 }
1324
1325 return pattern;
1326}
1327
1328QString KuitSemanticsPrivate::formatSubText (const QString &ptext,
1329 const OpenEl &oel,
1330 Kuit::FmtVar fmt,
1331 int numctx) const
1332{
1333 KuitSemanticsStaticData *s = semanticsStaticData;
1334
1335 if (oel.handling == OpenEl::Proper) {
1336 // Select formatting pattern.
1337 QString pattern = visualPattern(oel.tag, oel.akey, fmt);
1338
1339 // Some tags modify their text.
1340 QString mtext = modifyTagText(oel.formattedText, oel.tag, oel.avals,
1341 numctx, fmt);
1342
1343 using namespace Kuit;
1344
1345 // Format text according to pattern.
1346 QString ftext;
1347 if (oel.tag == Tag::Link && oel.avals.contains(Att::Url)) {
1348 ftext = pattern.arg(oel.avals[Att::Url], mtext);
1349 }
1350 else if (oel.tag == Tag::Command && oel.avals.contains(Att::Section)) {
1351 ftext = pattern.arg(mtext, oel.avals[Att::Section]);
1352 }
1353 else if (oel.tag == Tag::Email && oel.avals.contains(Att::Address)) {
1354 ftext = pattern.arg(mtext, oel.avals[Att::Address]);
1355 }
1356 else if (oel.tag == Tag::Note && oel.avals.contains(Att::Label)) {
1357 ftext = pattern.arg(oel.avals[Att::Label], mtext);
1358 }
1359 else if (oel.tag == Tag::Warning && oel.avals.contains(Att::Label)) {
1360 ftext = pattern.arg(oel.avals[Att::Label], mtext);
1361 }
1362 else {
1363 ftext = pattern.arg(mtext);
1364 }
1365
1366 // Handle leading newlines, if this is not start of the text
1367 // (ptext is the preceding text).
1368 if (!ptext.isEmpty() && s->leadingNewlines.contains(oel.tag)) {
1369 // Count number of present newlines.
1370 int pnumle, pnumtr, fnumle, fnumtr;
1371 countWrappingNewlines(ptext, pnumle, pnumtr);
1372 countWrappingNewlines(ftext, fnumle, fnumtr);
1373 // Number of leading newlines already present.
1374 int numle = pnumtr + fnumle;
1375 // The required extra newlines.
1376 QString strle;
1377 if (numle < s->leadingNewlines[oel.tag]) {
1378 strle = QString(s->leadingNewlines[oel.tag] - numle, QLatin1Char('\n'));
1379 }
1380 ftext = strle + ftext;
1381 }
1382
1383 return ftext;
1384 }
1385 else if (oel.handling == OpenEl::Ignored) {
1386 if (oel.name == QLatin1String("br") || oel.name == QLatin1String("hr")) {
1387 // Close these tags in-place (just for looks).
1388 return QLatin1Char('<') + oel.name + QLatin1String("/>");
1389 }
1390 else {
1391 return QLatin1Char('<') + oel.name + oel.astr + QLatin1Char('>')
1392 + oel.formattedText
1393 + QLatin1String("</") + oel.name + QLatin1Char('>');
1394 }
1395 }
1396 else { // oel.handling == OpenEl::Dropout
1397 return oel.formattedText;
1398 }
1399}
1400
1401void KuitSemanticsPrivate::countWrappingNewlines (const QString &text,
1402 int &numle, int &numtr)
1403{
1404 int len = text.length();
1405 // Number of newlines at start of text.
1406 numle = 0;
1407 while (numle < len && text[numle] == QLatin1Char('\n')) {
1408 ++numle;
1409 }
1410 // Number of newlines at end of text.
1411 numtr = 0;
1412 while (numtr < len && text[len - numtr - 1] == QLatin1Char('\n')) {
1413 ++numtr;
1414 }
1415}
1416
1417QString KuitSemanticsPrivate::modifyTagText (const QString &text,
1418 Kuit::TagVar tag,
1419 const QHash<Kuit::AttVar, QString> &avals,
1420 int numctx,
1421 Kuit::FmtVar fmt) const
1422{
1423 // numctx < 1 means that the number is not in numeric-id context.
1424 if ( (tag == Kuit::Tag::NumIntg || tag == Kuit::Tag::NumReal) \
1425 && numctx < 1)
1426 {
1427 int fieldWidth = avals.value(Kuit::Att::Width, QString(QLatin1Char('0'))).toInt();
1428 const QString fillStr = avals.value(Kuit::Att::Fill, QString(QLatin1Char(' ')));
1429 const QChar fillChar = !fillStr.isEmpty() ? fillStr[0] : QChar::fromLatin1(' ');
1430 return QString::fromLatin1("%1").arg(KGlobal::locale()->formatNumber(text, false),
1431 fieldWidth, fillChar);
1432 }
1433 else if (tag == Kuit::Tag::Filename) {
1434 return QDir::toNativeSeparators(text);
1435 }
1436 else if (tag == Kuit::Tag::Shortcut) {
1437 return KuitFormats::toKeyCombo(text, m_comboKeyDelim[fmt], m_keyNames);
1438 }
1439 else if (tag == Kuit::Tag::Interface) {
1440 return KuitFormats::toInterfacePath(text, m_guiPathDelim[fmt]);
1441 }
1442
1443 // Fell through, no modification.
1444 return text;
1445}
1446
1447QString KuitSemanticsPrivate::finalizeVisualText (const QString &final,
1448 Kuit::FmtVar fmt,
1449 bool hadQtTag,
1450 bool hadAnyHtmlTag) const
1451{
1452 KuitSemanticsStaticData *s = semanticsStaticData;
1453
1454 QString text = final;
1455
1456 // Resolve XML entities if format explicitly not rich
1457 // and no HTML tag encountered.
1458 if (fmt != Kuit::Fmt::Rich && !hadAnyHtmlTag)
1459 {
1460 static QRegExp staticEntRx(QLatin1String("&(" ENTITY_SUBRX ");"));
1461 // We have to have a local copy here, otherwise this function
1462 // will not be thread safe because QRegExp is not thread safe.
1463 QRegExp entRx = staticEntRx;
1464 int p = entRx.indexIn(text);
1465 QString plain;
1466 while (p >= 0) {
1467 QString ent = entRx.capturedTexts().at(1);
1468 plain.append(text.mid(0, p));
1469 text.remove(0, p + ent.length() + 2);
1470 if (ent.startsWith(QLatin1Char('#'))) { // numeric character entity
1471 QChar c;
1472 bool ok;
1473 if (ent[1] == QLatin1Char('x')) {
1474 c = QChar(ent.mid(2).toInt(&ok, 16));
1475 } else {
1476 c = QChar(ent.mid(1).toInt(&ok, 10));
1477 }
1478 if (ok) {
1479 plain.append(c);
1480 } else { // unknown Unicode point, leave as is
1481 plain.append(QLatin1Char('&') + ent + QLatin1Char(';'));
1482 }
1483 }
1484 else if (s->xmlEntities.contains(ent)) { // known entity
1485 plain.append(s->xmlEntities[ent]);
1486 } else { // unknown entity, just leave as is
1487 plain.append(QLatin1Char('&') + ent + QLatin1Char(';'));
1488 }
1489 p = entRx.indexIn(text);
1490 }
1491 plain.append(text);
1492 text = plain;
1493 }
1494
1495 // Add top rich tag if format explicitly rich or such tag encountered.
1496 if (fmt == Kuit::Fmt::Rich || hadQtTag) {
1497 text = QString::fromLatin1("<html>") + text + QLatin1String("</html>");
1498 }
1499
1500 return text;
1501}
1502
1503QString KuitSemanticsPrivate::salvageMarkup (const QString &text_,
1504 Kuit::FmtVar fmt) const
1505{
1506 KuitSemanticsStaticData *s = semanticsStaticData;
1507 QString text = text_;
1508 QString ntext;
1509 int pos;
1510
1511 // Resolve KUIT tags simple-mindedly.
1512
1513 // - tags with content
1514 static QRegExp staticWrapRx(QLatin1String("(<\\s*(\\w+)\\b([^>]*)>)(.*)(<\\s*/\\s*\\2\\s*>)"));
1515 QRegExp wrapRx = staticWrapRx; // for thread-safety
1516 wrapRx.setMinimal(true);
1517 pos = 0;
1518 ntext.clear();
1519 while (true) {
1520 int previousPos = pos;
1521 pos = wrapRx.indexIn(text, previousPos);
1522 if (pos < 0) {
1523 ntext += text.mid(previousPos);
1524 break;
1525 }
1526 ntext += text.mid(previousPos, pos - previousPos);
1527 const QStringList capts = wrapRx.capturedTexts();
1528 QString tagname = capts[2].toLower();
1529 QString content = salvageMarkup(capts[4], fmt);
1530 if (s->knownTags.contains(tagname)) {
1531 // Select formatting pattern.
1532 // TODO: Do not ignore attributes (in capts[3]).
1533 QString pattern = visualPattern(s->knownTags[tagname], 0, fmt);
1534 ntext += pattern.arg(content);
1535 } else {
1536 ntext += capts[1] + content + capts[5];
1537 }
1538 pos += wrapRx.matchedLength();
1539 }
1540 text = ntext;
1541
1542 // - content-less tags
1543 static QRegExp staticNowrRx(QLatin1String("<\\s*(\\w+)\\b([^>]*)/\\s*>"));
1544 QRegExp nowrRx = staticNowrRx; // for thread-safety
1545 nowrRx.setMinimal(true);
1546 pos = 0;
1547 ntext.clear();
1548 while (true) {
1549 int previousPos = pos;
1550 pos = nowrRx.indexIn(text, previousPos);
1551 if (pos < 0) {
1552 ntext += text.mid(previousPos);
1553 break;
1554 }
1555 ntext += text.mid(previousPos, pos - previousPos);
1556 const QStringList capts = nowrRx.capturedTexts();
1557 QString tagname = capts[1].toLower();
1558 if (s->knownTags.contains(tagname)) {
1559 QString pattern = visualPattern(s->knownTags[tagname], 0, fmt);
1560 ntext += pattern.arg(QString());
1561 } else {
1562 ntext += capts[0];
1563 }
1564 pos += nowrRx.matchedLength();
1565 }
1566 text = ntext;
1567
1568 return text;
1569}
1570
1571// -----------------------------------------------------------------------------
1572// The KuitSemantics methods, only delegate to KuitSemanticsPrivate.
1573
1574KuitSemantics::KuitSemantics (const QString &lang)
1575: d(new KuitSemanticsPrivate(lang))
1576{
1577}
1578
1579KuitSemantics::~KuitSemantics ()
1580{
1581 delete d;
1582}
1583
1584QString KuitSemantics::format (const QString &text, const QString &ctxt) const
1585{
1586 return d->format(text, ctxt);
1587}
1588
1589bool KuitSemantics::mightBeRichText (const QString &text)
1590{
1591 KuitSemanticsStaticData *s = semanticsStaticData;
1592
1593 // Check by appearance of a valid XML entity at first ampersand.
1594 int p1 = text.indexOf(QLatin1Char('&'));
1595 if (p1 >= 0) {
1596 p1 += 1;
1597 int p2 = text.indexOf(QLatin1Char(';'), p1);
1598 return (p2 > p1 && s->xmlEntities.contains(text.mid(p1, p2 - p1)));
1599 }
1600
1601 // Check by appearance of a valid Qt rich-text tag at first less-than.
1602 int tlen = text.length();
1603 p1 = text.indexOf(QLatin1Char('<'));
1604 if (p1 >= 0) {
1605 p1 += 1;
1606 // Also allow first tag to be closing tag,
1607 // e.g. in case the text is pieced up with list.join("</foo><foo>")
1608 bool closing = false;
1609 while (p1 < tlen && (text[p1].isSpace() || text[p1] == QLatin1Char('/'))) {
1610 if (text[p1] == QLatin1Char('/')) {
1611 if (!closing) {
1612 closing = true;
1613 } else {
1614 return false;
1615 }
1616 }
1617 ++p1;
1618 }
1619 for (int p2 = p1; p2 < tlen; ++p2) {
1620 QChar c = text[p2];
1621 if (c == QLatin1Char('>') || (!closing && c == QLatin1Char('/')) || c.isSpace()) {
1622 return s->qtHtmlTagNames.contains(text.mid(p1, p2 - p1));
1623 } else if (!c.isLetter()) {
1624 return false;
1625 }
1626 }
1627 return false;
1628 }
1629
1630 return false;
1631}
1632
1633QString KuitSemantics::escape (const QString &text)
1634{
1635 int tlen = text.length();
1636 QString ntext;
1637 ntext.reserve(tlen);
1638 for (int i = 0; i < tlen; ++i) {
1639 QChar c = text[i];
1640 if (c == QLatin1Char('&')) {
1641 ntext += QLatin1String("&amp;");
1642 } else if (c == QLatin1Char('<')) {
1643 ntext += QLatin1String("&lt;");
1644 } else if (c == QLatin1Char('>')) {
1645 ntext += QLatin1String("&gt;");
1646 } else if (c == QLatin1Char('\'')) {
1647 ntext += QLatin1String("&apos;");
1648 } else if (c == QLatin1Char('"')) {
1649 ntext += QLatin1String("&quot;");
1650 } else {
1651 ntext += c;
1652 }
1653 }
1654
1655 return ntext;
1656}
KCatalog
This class abstracts a gettext message catalog.
Definition: kcatalog_p.h:36
KuitSemantics::~KuitSemantics
~KuitSemantics()
Destructor.
Definition: kuitsemantics.cpp:1579
KuitSemantics::mightBeRichText
static bool mightBeRichText(const QString &text)
Poor man's version of Qt::mightBeRichText() (cannot link to QtGui).
Definition: kuitsemantics.cpp:1589
KuitSemantics::KuitSemantics
KuitSemantics(const QString &lang)
Constructor.
Definition: kuitsemantics.cpp:1574
KuitSemantics::escape
static QString escape(const QString &text)
Convert &, ", ', <, > characters into XML entities &, <, >, ', ", respectively.
Definition: kuitsemantics.cpp:1633
KuitSemantics::format
QString format(const QString &text, const QString &ctxt) const
Transforms the semantic markup in the given text into visual formatting.
Definition: kuitsemantics.cpp:1584
QHash
Definition: ksycocafactory.h:28
QList
Definition: kaboutdata.h:33
QSet
Definition: k3resolver.h:41
QStringList
QString
K_GLOBAL_STATIC
#define K_GLOBAL_STATIC(TYPE, NAME)
This macro makes it easy to use non-POD types as global statics.
Definition: kglobal.h:221
kDebug
#define kDebug
Definition: kdebug.h:316
kcatalog_p.h
Status
Status
Definition: kdatetime.cpp:76
kdebug.h
kglobal.h
klocale.h
kuitformats_p.h
shorten
static QString shorten(const QString &str)
Definition: kuitsemantics.cpp:44
INLINES
#define INLINES
SETUP_ATT
#define SETUP_ATT(att, name)
SET_PATTERN
#define SET_PATTERN(tag, atts, fmt, ctxt_ptrn)
I18N_NOOP2
#define I18N_NOOP2(ctxt, msg)
SETUP_TAG
#define SETUP_TAG(tag, name, atts, subs)
SETUP_CUE
#define SETUP_CUE(cue, name)
SETUP_ROLCUEFMT
#define SETUP_ROLCUEFMT(rol, cue, fmt)
QL1S
#define QL1S(x)
Definition: kuitsemantics.cpp:39
SETUP_TAG_NL
#define SETUP_TAG_NL(tag, nlead)
SET_KEYNAME
#define SET_KEYNAME(rawname)
SETUP_ROL
#define SETUP_ROL(rol, name, fmt, cues)
SETUP_FMT
#define SETUP_FMT(fmt, name)
XXXX_NOOP2
#define XXXX_NOOP2(ctxt, msg)
ENTITY_SUBRX
#define ENTITY_SUBRX
Definition: kuitsemantics.cpp:1110
kuitsemantics_p.h
KUIT_NUMREAL
#define KUIT_NUMREAL
Definition: kuitsemantics_p.h:88
KUIT_NUMINTG
#define KUIT_NUMINTG
Definition: kuitsemantics_p.h:87
KGlobal::locale
KLocale * locale()
Returns the global locale object.
Definition: kglobal.cpp:170
KuitFormats::toInterfacePath
QString toInterfacePath(const QString &inpstr, const QString &delim)
Reformat GUI element path.
Definition: kuitformats.cpp:59
KuitFormats::toKeyCombo
QString toKeyCombo(const QString &shstr, const QString &delim, const QHash< QString, QString > &keydict)
Reformat keyboard shortcut.
Definition: kuitformats.cpp:29
Kuit::Att::Var
Var
Definition: kuitsemantics.cpp:92
Kuit::Att::Url
@ Url
Definition: kuitsemantics.cpp:94
Kuit::Att::Address
@ Address
Definition: kuitsemantics.cpp:94
Kuit::Att::Strong
@ Strong
Definition: kuitsemantics.cpp:94
Kuit::Att::Fill
@ Fill
Definition: kuitsemantics.cpp:95
Kuit::Att::Ctx
@ Ctx
Definition: kuitsemantics.cpp:94
Kuit::Att::None
@ None
Definition: kuitsemantics.cpp:93
Kuit::Att::Width
@ Width
Definition: kuitsemantics.cpp:95
Kuit::Att::Section
@ Section
Definition: kuitsemantics.cpp:94
Kuit::Att::Label
@ Label
Definition: kuitsemantics.cpp:94
Kuit::Cue::Var
Var
Definition: kuitsemantics.cpp:107
Kuit::Cue::Status
@ Status
Definition: kuitsemantics.cpp:114
Kuit::Cue::Radio
@ Radio
Definition: kuitsemantics.cpp:112
Kuit::Cue::Shell
@ Shell
Definition: kuitsemantics.cpp:114
Kuit::Cue::Tooltip
@ Tooltip
Definition: kuitsemantics.cpp:114
Kuit::Cue::Intoolbar
@ Intoolbar
Definition: kuitsemantics.cpp:109
Kuit::Cue::Whatsthis
@ Whatsthis
Definition: kuitsemantics.cpp:114
Kuit::Cue::Inmenu
@ Inmenu
Definition: kuitsemantics.cpp:109
Kuit::Cue::Listbox
@ Listbox
Definition: kuitsemantics.cpp:111
Kuit::Cue::None
@ None
Definition: kuitsemantics.cpp:108
Kuit::Cue::Check
@ Check
Definition: kuitsemantics.cpp:112
Kuit::Cue::Chooser
@ Chooser
Definition: kuitsemantics.cpp:111
Kuit::Cue::Slider
@ Slider
Definition: kuitsemantics.cpp:111
Kuit::Cue::Credit
@ Credit
Definition: kuitsemantics.cpp:114
Kuit::Cue::Tipoftheday
@ Tipoftheday
Definition: kuitsemantics.cpp:114
Kuit::Cue::Menu
@ Menu
Definition: kuitsemantics.cpp:110
Kuit::Cue::Column
@ Column
Definition: kuitsemantics.cpp:110
Kuit::Cue::Intext
@ Intext
Definition: kuitsemantics.cpp:113
Kuit::Cue::Progress
@ Progress
Definition: kuitsemantics.cpp:114
Kuit::Cue::Intable
@ Intable
Definition: kuitsemantics.cpp:113
Kuit::Cue::Button
@ Button
Definition: kuitsemantics.cpp:109
Kuit::Cue::Inlistbox
@ Inlistbox
Definition: kuitsemantics.cpp:113
Kuit::Cue::Inrange
@ Inrange
Definition: kuitsemantics.cpp:113
Kuit::Cue::Row
@ Row
Definition: kuitsemantics.cpp:110
Kuit::Cue::Spinbox
@ Spinbox
Definition: kuitsemantics.cpp:111
Kuit::Cue::Window
@ Window
Definition: kuitsemantics.cpp:110
Kuit::Cue::Textbox
@ Textbox
Definition: kuitsemantics.cpp:111
Kuit::Cue::Tab
@ Tab
Definition: kuitsemantics.cpp:110
Kuit::Cue::Group
@ Group
Definition: kuitsemantics.cpp:110
Kuit::Fmt::Var
Var
Definition: kuitsemantics.cpp:119
Kuit::Fmt::Plain
@ Plain
Definition: kuitsemantics.cpp:120
Kuit::Fmt::Term
@ Term
Definition: kuitsemantics.cpp:120
Kuit::Fmt::None
@ None
Definition: kuitsemantics.cpp:120
Kuit::Fmt::Rich
@ Rich
Definition: kuitsemantics.cpp:120
Kuit::Rol::Var
Var
Definition: kuitsemantics.cpp:100
Kuit::Rol::Info
@ Info
Definition: kuitsemantics.cpp:102
Kuit::Rol::None
@ None
Definition: kuitsemantics.cpp:101
Kuit::Rol::Option
@ Option
Definition: kuitsemantics.cpp:102
Kuit::Rol::Title
@ Title
Definition: kuitsemantics.cpp:102
Kuit::Rol::Item
@ Item
Definition: kuitsemantics.cpp:102
Kuit::Rol::Label
@ Label
Definition: kuitsemantics.cpp:102
Kuit::Rol::Action
@ Action
Definition: kuitsemantics.cpp:102
Kuit::Tag::Var
Var
Definition: kuitsemantics.cpp:81
Kuit::Tag::Warning
@ Warning
Definition: kuitsemantics.cpp:84
Kuit::Tag::TopLong
@ TopLong
Definition: kuitsemantics.cpp:83
Kuit::Tag::Item
@ Item
Definition: kuitsemantics.cpp:84
Kuit::Tag::Command
@ Command
Definition: kuitsemantics.cpp:85
Kuit::Tag::Subtitle
@ Subtitle
Definition: kuitsemantics.cpp:84
Kuit::Tag::List
@ List
Definition: kuitsemantics.cpp:84
Kuit::Tag::Message
@ Message
Definition: kuitsemantics.cpp:86
Kuit::Tag::Para
@ Para
Definition: kuitsemantics.cpp:84
Kuit::Tag::Note
@ Note
Definition: kuitsemantics.cpp:84
Kuit::Tag::NumReal
@ NumReal
Definition: kuitsemantics.cpp:87
Kuit::Tag::Envar
@ Envar
Definition: kuitsemantics.cpp:86
Kuit::Tag::Email
@ Email
Definition: kuitsemantics.cpp:86
Kuit::Tag::Link
@ Link
Definition: kuitsemantics.cpp:84
Kuit::Tag::Application
@ Application
Definition: kuitsemantics.cpp:85
Kuit::Tag::Numid
@ Numid
Definition: kuitsemantics.cpp:86
Kuit::Tag::TopShort
@ TopShort
Definition: kuitsemantics.cpp:83
Kuit::Tag::Shortcut
@ Shortcut
Definition: kuitsemantics.cpp:85
Kuit::Tag::Filename
@ Filename
Definition: kuitsemantics.cpp:85
Kuit::Tag::Placeholder
@ Placeholder
Definition: kuitsemantics.cpp:86
Kuit::Tag::NumIntg
@ NumIntg
Definition: kuitsemantics.cpp:87
Kuit::Tag::Title
@ Title
Definition: kuitsemantics.cpp:84
Kuit::Tag::Resource
@ Resource
Definition: kuitsemantics.cpp:85
Kuit::Tag::None
@ None
Definition: kuitsemantics.cpp:82
Kuit::Tag::Bcode
@ Bcode
Definition: kuitsemantics.cpp:85
Kuit::Tag::Emphasis
@ Emphasis
Definition: kuitsemantics.cpp:86
Kuit::Tag::Icode
@ Icode
Definition: kuitsemantics.cpp:85
Kuit::Tag::Interface
@ Interface
Definition: kuitsemantics.cpp:86
Kuit::Tag::Nl
@ Nl
Definition: kuitsemantics.cpp:86
Kuit
Definition: kuitsemantics.cpp:78
Kuit::TagVar
Tag::Var TagVar
Definition: kuitsemantics.cpp:124
Kuit::CueVar
Cue::Var CueVar
Definition: kuitsemantics.cpp:127
Kuit::RolVar
Rol::Var RolVar
Definition: kuitsemantics.cpp:126
Kuit::AttVar
Att::Var AttVar
Definition: kuitsemantics.cpp:125
Kuit::FmtVar
Fmt::Var FmtVar
Definition: kuitsemantics.cpp:128
Action
Definition: policy-gen.h:28
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal