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

KDECore

  • sources
  • kde-4.14
  • kdelibs
  • 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).
44 static 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.
54 class 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.
78 namespace 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 
134 class 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 
163 KuitSemanticsStaticData::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 
350 K_GLOBAL_STATIC(KuitSemanticsStaticData, semanticsStaticData)
351 
352 
353 // -----------------------------------------------------------------------------
354 // The KuitSemanticsPrivate methods, they do the work.
355 
356 class 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 
453 KuitSemanticsPrivate::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 
477 QString 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 
485 void 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 
803 void 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 
882 QString 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 
914 int 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 
927 Kuit::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 
1029 Kuit::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 
1046 QString 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 
1112 QString 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 
1232 KuitSemanticsPrivate::OpenEl
1233 KuitSemanticsPrivate::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 
1311 QString 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 
1328 QString 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 
1401 void 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 
1417 QString 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 
1447 QString 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 
1503 QString 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 
1574 KuitSemantics::KuitSemantics (const QString &lang)
1575 : d(new KuitSemanticsPrivate(lang))
1576 {
1577 }
1578 
1579 KuitSemantics::~KuitSemantics ()
1580 {
1581  delete d;
1582 }
1583 
1584 QString KuitSemantics::format (const QString &text, const QString &ctxt) const
1585 {
1586  return d->format(text, ctxt);
1587 }
1588 
1589 bool 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 
1633 QString 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 }
Kuit::Cue::Group
Definition: kuitsemantics.cpp:110
Kuit::Att::None
Definition: kuitsemantics.cpp:93
Kuit::Tag::Placeholder
Definition: kuitsemantics.cpp:86
QXmlStreamReader::atEnd
bool atEnd() const
Kuit::Tag::NumReal
Definition: kuitsemantics.cpp:87
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QXmlStreamReader::errorString
QString errorString() const
QDir::toNativeSeparators
QString toNativeSeparators(const QString &pathName)
QString::append
QString & append(QChar ch)
Kuit::Tag::Emphasis
Definition: kuitsemantics.cpp:86
Kuit::Fmt::None
Definition: kuitsemantics.cpp:120
Kuit::Tag::Var
Var
Definition: kuitsemantics.cpp:81
Kuit::Cue::Listbox
Definition: kuitsemantics.cpp:111
SET_PATTERN
#define SET_PATTERN(tag, atts, fmt, ctxt_ptrn)
Kuit::FmtVar
Fmt::Var FmtVar
Definition: kuitsemantics.cpp:128
kdebug.h
SETUP_TAG_NL
#define SETUP_TAG_NL(tag, nlead)
Kuit::CueVar
Cue::Var CueVar
Definition: kuitsemantics.cpp:127
Kuit::Tag::Message
Definition: kuitsemantics.cpp:86
QStack::pop
T pop()
KuitFormats::toKeyCombo
QString toKeyCombo(const QString &shstr, const QString &delim, const QHash< QString, QString > &keydict)
Reformat keyboard shortcut.
Definition: kuitformats.cpp:29
KUIT_NUMREAL
#define KUIT_NUMREAL
Definition: kuitsemantics_p.h:88
Kuit::Tag::Numid
Definition: kuitsemantics.cpp:86
Kuit::Tag::Application
Definition: kuitsemantics.cpp:85
Kuit::Tag::Subtitle
Definition: kuitsemantics.cpp:84
kuitsemantics_p.h
Kuit::Rol::Info
Definition: kuitsemantics.cpp:102
Kuit::Att::Label
Definition: kuitsemantics.cpp:94
Kuit::Att::Url
Definition: kuitsemantics.cpp:94
QRegExp::setMinimal
void setMinimal(bool minimal)
KuitSemantics::escape
static QString escape(const QString &text)
Convert &, ", ', <, > characters into XML entities &, <, >, ', ", respectively.
Definition: kuitsemantics.cpp:1633
Kuit::Tag::Nl
Definition: kuitsemantics.cpp:86
QChar
kuitformats_p.h
Kuit::Tag::Warning
Definition: kuitsemantics.cpp:84
QStringRef::toString
QString toString() const
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
QStack::push
void push(const T &t)
Kuit::Att::Width
Definition: kuitsemantics.cpp:95
QList::at
const T & at(int i) const
SETUP_ROLCUEFMT
#define SETUP_ROLCUEFMT(rol, cue, fmt)
Kuit::Tag::NumIntg
Definition: kuitsemantics.cpp:87
KuitSemantics::KuitSemantics
KuitSemantics(const QString &lang)
Constructor.
Definition: kuitsemantics.cpp:1574
Kuit::Fmt::Var
Var
Definition: kuitsemantics.cpp:119
Kuit::Tag::Command
Definition: kuitsemantics.cpp:85
XXXX_NOOP2
#define XXXX_NOOP2(ctxt, msg)
Kuit::Rol::Title
Definition: kuitsemantics.cpp:102
QString::remove
QString & remove(int position, int n)
Kuit::Cue::Inrange
Definition: kuitsemantics.cpp:113
klocale.h
Kuit::Cue::Check
Definition: kuitsemantics.cpp:112
Kuit::Cue::Intext
Definition: kuitsemantics.cpp:113
ENTITY_SUBRX
#define ENTITY_SUBRX
Definition: kuitsemantics.cpp:1110
Kuit::Cue::Tab
Definition: kuitsemantics.cpp:110
Kuit::Tag::Para
Definition: kuitsemantics.cpp:84
QList::size
int size() const
Kuit::Cue::Shell
Definition: kuitsemantics.cpp:114
QChar::isLetter
bool isLetter() const
QStringRef
QString::clear
void clear()
Kuit::TagVar
Tag::Var TagVar
Definition: kuitsemantics.cpp:124
QRegExp::matchedLength
int matchedLength() const
Kuit::Tag::None
Definition: kuitsemantics.cpp:82
QRegExp::indexIn
int indexIn(const QString &str, int offset, CaretMode caretMode) const
Kuit::Tag::Title
Definition: kuitsemantics.cpp:84
Kuit::Cue::Progress
Definition: kuitsemantics.cpp:114
QRegExp
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
kglobal.h
Kuit::Cue::Inlistbox
Definition: kuitsemantics.cpp:113
SETUP_FMT
#define SETUP_FMT(fmt, name)
SET_KEYNAME
#define SET_KEYNAME(rawname)
QXmlStreamAttribute
QChar::isSpace
bool isSpace() const
Kuit::Cue::Slider
Definition: kuitsemantics.cpp:111
Kuit::Tag::Envar
Definition: kuitsemantics.cpp:86
QHash< QString, QString >
Status
Status
Definition: kdatetime.cpp:76
Kuit::Cue::Credit
Definition: kuitsemantics.cpp:114
KUIT_NUMINTG
#define KUIT_NUMINTG
Definition: kuitsemantics_p.h:87
Kuit::Att::Address
Definition: kuitsemantics.cpp:94
Kuit::Rol::None
Definition: kuitsemantics.cpp:101
QRegExp::capturedTexts
QStringList capturedTexts() const
Kuit::Rol::Action
Definition: kuitsemantics.cpp:102
QChar::fromLatin1
QChar fromLatin1(char c)
KuitFormats::toInterfacePath
QString toInterfacePath(const QString &inpstr, const QString &delim)
Reformat GUI element path.
Definition: kuitformats.cpp:59
QString::toInt
int toInt(bool *ok, int base) const
Kuit::Tag::Bcode
Definition: kuitsemantics.cpp:85
QString::isEmpty
bool isEmpty() const
QString::trimmed
QString trimmed() const
Kuit::Rol::Option
Definition: kuitsemantics.cpp:102
Kuit::Cue::Tooltip
Definition: kuitsemantics.cpp:114
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
Kuit::Tag::Interface
Definition: kuitsemantics.cpp:86
Kuit::Tag::Email
Definition: kuitsemantics.cpp:86
Kuit::Cue::Column
Definition: kuitsemantics.cpp:110
QXmlStreamReader::isCharacters
bool isCharacters() const
Kuit::Tag::Resource
Definition: kuitsemantics.cpp:85
Kuit::Tag::Icode
Definition: kuitsemantics.cpp:85
QXmlStreamReader::setEntityResolver
void setEntityResolver(QXmlStreamEntityResolver *resolver)
QSet< QString >
QString
QList
Definition: kaboutdata.h:33
QXmlStreamReader::readNext
TokenType readNext()
Kuit::Att::Strong
Definition: kuitsemantics.cpp:94
Kuit::Cue::Spinbox
Definition: kuitsemantics.cpp:111
QStringList
Action
Definition: policy-gen.h:28
QString::toLower
QString toLower() const
QHash::value
const T value(const Key &key) const
Kuit::Rol::Var
Var
Definition: kuitsemantics.cpp:100
KuitSemantics::mightBeRichText
static bool mightBeRichText(const QString &text)
Poor man's version of Qt::mightBeRichText() (cannot link to QtGui).
Definition: kuitsemantics.cpp:1589
SETUP_ROL
#define SETUP_ROL(rol, name, fmt, cues)
QLatin1Char
QChar::toLower
QChar toLower() const
Kuit::Cue::Button
Definition: kuitsemantics.cpp:109
Kuit::Att::Var
Var
Definition: kuitsemantics.cpp:92
kcatalog_p.h
Kuit::Cue::None
Definition: kuitsemantics.cpp:108
KGlobal::locale
KLocale * locale()
Returns the global locale object.
Definition: kglobal.cpp:170
QXmlStreamReader
Kuit::Cue::Inmenu
Definition: kuitsemantics.cpp:109
Kuit::Tag::Note
Definition: kuitsemantics.cpp:84
Kuit::Cue::Intable
Definition: kuitsemantics.cpp:113
QXmlStreamAttribute::name
QStringRef name() const
QXmlStreamReader::isStartElement
bool isStartElement() const
Kuit::Tag::TopLong
Definition: kuitsemantics.cpp:83
Kuit::Fmt::Rich
Definition: kuitsemantics.cpp:120
QString::mid
QString mid(int position, int n) const
Kuit::Att::Ctx
Definition: kuitsemantics.cpp:94
Kuit::RolVar
Rol::Var RolVar
Definition: kuitsemantics.cpp:126
QLatin1String
Kuit::Cue::Chooser
Definition: kuitsemantics.cpp:111
shorten
static QString shorten(const QString &str)
Definition: kuitsemantics.cpp:44
Kuit::Cue::Window
Definition: kuitsemantics.cpp:110
QXmlStreamReader::hasError
bool hasError() const
Kuit::Cue::Row
Definition: kuitsemantics.cpp:110
QVector::isEmpty
bool isEmpty() const
QXmlStreamEntityResolver::resolveUndeclaredEntity
virtual QString resolveUndeclaredEntity(const QString &name)
Kuit::AttVar
Att::Var AttVar
Definition: kuitsemantics.cpp:125
QString::at
const QChar at(int position) const
QList::last
T & last()
Kuit::Cue::Menu
Definition: kuitsemantics.cpp:110
SETUP_TAG
#define SETUP_TAG(tag, name, atts, subs)
Kuit::Cue::Intoolbar
Definition: kuitsemantics.cpp:109
SETUP_CUE
#define SETUP_CUE(cue, name)
Kuit::Rol::Item
Definition: kuitsemantics.cpp:102
QXmlStreamReader::text
QStringRef text() const
KuitSemantics::~KuitSemantics
~KuitSemantics()
Destructor.
Definition: kuitsemantics.cpp:1579
SETUP_ATT
#define SETUP_ATT(att, name)
Kuit::Fmt::Plain
Definition: kuitsemantics.cpp:120
Kuit::Cue::Var
Var
Definition: kuitsemantics.cpp:107
QString::length
int length() const
Kuit::Att::Section
Definition: kuitsemantics.cpp:94
QString::reserve
void reserve(int size)
Kuit::Tag::List
Definition: kuitsemantics.cpp:84
Kuit::Cue::Whatsthis
Definition: kuitsemantics.cpp:114
QString::left
QString left(int n) const
KCatalog
This class abstracts a gettext message catalog.
Definition: kcatalog_p.h:35
Kuit::Tag::Shortcut
Definition: kuitsemantics.cpp:85
QSet::toList
QList< T > toList() const
QXmlStreamReader::attributes
QXmlStreamAttributes attributes() const
QString::fromLatin1
QString fromLatin1(const char *str, int size)
Kuit::Cue::Textbox
Definition: kuitsemantics.cpp:111
Kuit::Tag::Item
Definition: kuitsemantics.cpp:84
QXmlStreamAttribute::value
QStringRef value() const
kDebug
#define kDebug
Definition: kdebug.h:316
QVector::size
int size() const
Kuit::Tag::Link
Definition: kuitsemantics.cpp:84
Kuit::Cue::Tipoftheday
Definition: kuitsemantics.cpp:114
INLINES
#define INLINES
QXmlStreamReader::name
QStringRef name() const
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
Kuit::Fmt::Term
Definition: kuitsemantics.cpp:120
Kuit::Tag::Filename
Definition: kuitsemantics.cpp:85
Kuit::Cue::Status
Definition: kuitsemantics.cpp:114
Kuit::Cue::Radio
Definition: kuitsemantics.cpp:112
Kuit::Tag::TopShort
Definition: kuitsemantics.cpp:83
Kuit::Att::Fill
Definition: kuitsemantics.cpp:95
QXmlStreamEntityResolver
Kuit::Rol::Label
Definition: kuitsemantics.cpp:102
QStack
I18N_NOOP2
#define I18N_NOOP2(ctxt, msg)
QL1S
#define QL1S(x)
Definition: kuitsemantics.cpp:39
QXmlStreamReader::isEndElement
bool isEndElement() const
QStack::top
T & top()
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:22:12 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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

Search



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