[KLF Application][KLF Tools][KLF Backend][KLF Home]
KLatexFormula Project
klflatexsymbols.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * file klflatexsymbols.cpp
3  * This file is part of the KLatexFormula Project.
4  * Copyright (C) 2011 by Philippe Faist
5  * philippe.faist@bluewin.ch
6  * *
7  * This program is free software; you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation; either version 2 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program; if not, write to the *
19  * Free Software Foundation, Inc., *
20  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21  ***************************************************************************/
22 /* $Id: klflatexsymbols.cpp 603 2011-02-26 23:14:55Z phfaist $ */
23 
24 #include <stdio.h>
25 
26 #include <QFile>
27 #include <QDir>
28 #include <QTextStream>
29 #include <QScrollArea>
30 #include <QList>
31 #include <QStringList>
32 #include <QProgressDialog>
33 #include <QGridLayout>
34 #include <QPushButton>
35 #include <QMap>
36 #include <QStackedWidget>
37 #include <QLineEdit>
38 #include <QMessageBox>
39 #include <QScrollBar>
40 #include <QApplication>
41 #include <QCloseEvent>
42 #include <QDebug>
43 #include <QPainter>
44 #include <QPlastiqueStyle>
45 
46 #include <QDomDocument>
47 #include <QDomElement>
48 
49 #include <klfbackend.h>
50 
51 #include <ui_klflatexsymbols.h>
52 
53 #include <klfpixmapbutton.h>
54 #include "klfmain.h"
55 #include "klfconfig.h"
56 #include "klflatexsymbols.h"
57 
58 
59 
60 // ------------------
61 
62 
64  : symbol(), preamble(), textmode(false), bbexpand(), hidden(false)
65 {
66  // preamble
67  QDomNodeList usepackagelist = e.elementsByTagName("usepackage");
68  int k;
69  for (k = 0; k < usepackagelist.size(); ++k) {
70  QString package = usepackagelist.at(k).toElement().attribute("name");
71  if (package[0] == '[' || package[0] == '{')
72  preamble.append(QString::fromAscii("\\usepackage%1").arg(package));
73  else
74  preamble.append(QString::fromAscii("\\usepackage{%1}").arg(package));
75  }
76  QDomNodeList preamblelinelist = e.elementsByTagName("preambleline");
77  for (k = 0; k < preamblelinelist.size(); ++k) {
78  preamble.append(preamblelinelist.at(k).toElement().text());
79  }
80  // textmode
81  if (e.attribute("textmode") == "true")
82  textmode = true;
83  else
84  textmode = false;
85 
86  if (e.elementsByTagName("hidden").size() > 0)
87  hidden = true;
88 
89  // bb offset
90  QDomNodeList bblist = e.elementsByTagName("bb");
91  if (bblist.size() > 1) {
92  fprintf(stderr, "WARNING: Expected at most single <bb expand=\"..\"/> item!\n");
93  }
94  if (bblist.size()) {
95  sscanf(bblist.at(0).toElement().attribute("expand").toLatin1().constData(), "%d,%d,%d,%d",
97  }
98 
99  // latex code
100  QDomNodeList latexlist = e.elementsByTagName("latex");
101  if (latexlist.size() != 1) {
102  fprintf(stderr, "WARNING: Expected single <latex>...</latex> in symbol entry!\n");
103  }
104  if (latexlist.size() == 0)
105  return;
106  symbol = latexlist.at(0).toElement().text();
107 
108  klfDbg("read symbol "<<symbol<<" hidden="<<hidden);
109 }
110 
111 KLF_EXPORT bool operator==(const KLFLatexSymbol& a, const KLFLatexSymbol& b)
112 {
113  return a.symbol == b.symbol &&
114  a.textmode == b.textmode &&
115  a.preamble == b.preamble &&
116  a.bbexpand.t == b.bbexpand.t &&
117  a.bbexpand.r == b.bbexpand.r &&
118  a.bbexpand.b == b.bbexpand.b &&
119  a.bbexpand.l == b.bbexpand.l &&
120  a.hidden == b.hidden;
121 }
122 
123 KLF_EXPORT bool operator<(const KLFLatexSymbol& a, const KLFLatexSymbol& b)
124 {
125  if (a.symbol != b.symbol)
126  return a.symbol < b.symbol;
127  if (a.textmode != b.textmode)
128  return a.textmode < b.textmode;
129  if (a.preamble.size() != b.preamble.size())
130  return a.preamble.size() < b.preamble.size();
131  int k;
132  for (k = 0; k < a.preamble.size(); ++k)
133  if (a.preamble[k] != b.preamble[k])
134  return a.preamble[k] < b.preamble[k];
135  // a and b seem to be equal
136  return false;
137 }
138 
140 {
141  return stream << s.symbol << s.preamble << (quint8)s.textmode
142  << (qint16)s.bbexpand.t << (qint16)s.bbexpand.r
143  << (qint16)s.bbexpand.b << (qint16)s.bbexpand.l << (quint8)s.hidden;
144 }
145 
147 {
148  quint8 textmode, hidden;
149  struct { qint16 t, r, b, l; } readbbexpand;
150  stream >> s.symbol >> s.preamble >> textmode >> readbbexpand.t >> readbbexpand.r
151  >> readbbexpand.b >> readbbexpand.l >> hidden;
152  s.bbexpand.t = readbbexpand.t;
153  s.bbexpand.r = readbbexpand.r;
154  s.bbexpand.b = readbbexpand.b;
155  s.bbexpand.l = readbbexpand.l;
156  s.textmode = textmode;
157  s.hidden = hidden;
158  return stream;
159 }
160 
161 
162 
163 // -----------------------------------------------------------
164 
165 
166 KLFLatexSymbolsCache * KLFLatexSymbolsCache::staticCache = NULL;
167 
170 {
171  if (__rel_cache_file.isEmpty())
172  __rel_cache_file =
173  QString("/symbolspixmapcache-klf%1").arg(KLF_DATA_STREAM_APP_VERSION);
174  return __rel_cache_file;
175 }
176 
177 KLFLatexSymbolsCache::KLFLatexSymbolsCache()
178 {
180  // load the cache
181 
182  QStringList cachefiles;
183  cachefiles
185  << ":/data/symbolspixmapcache_base" ;
186  int k;
187  bool ok = false;
188  for (k = 0; !ok && k < cachefiles.size(); ++k) {
189  // ??: do the two attempts here apply a datastream version to the header only, or to
190  // the data too?
191  klfDbg("trying to load from "<<cachefiles[k]) ;
192  ok = ( loadCacheFrom(cachefiles[k], QDataStream::Qt_4_4)
194  if (!ok) {
195  klfDbg("trying to load from "<<cachefiles[k]<<" with default header datastream version") ;
196  ok = ( loadCacheFrom(cachefiles[k], -1)
198  }
199  }
200  if ( ! ok ) {
201  qWarning() << KLF_FUNC_NAME << ": error finding and reading cache file!";
202  }
203 
204  flag_modified = false;
205 }
206 
207 int KLFLatexSymbolsCache::loadCacheStream(QDataStream& stream)
208 {
209  QString readHeader;
210  QString readCompatKLFVersion;
211  bool r = klfDataStreamReadHeader(stream, QStringList()<<"KLATEXFORMULA_SYMBOLS_PIXMAP_CACHE",
212  &readHeader, &readCompatKLFVersion);
213  if (!r) {
214  klfDbg("failed to read symbolscache data header. readHeader="<<readHeader
215  <<", readcompatklfver="<<readCompatKLFVersion) ;
216  if (readHeader.isEmpty() || readCompatKLFVersion.isEmpty())
217  return BadHeader;
218  // otherwise, it's a bad version error
219  return BadVersion;
220  }
221 
222  // stream is now ready to read
223 
224  stream >> cache;
225 
226  flag_modified = false;
227  return 0;
228 }
229 
230 int KLFLatexSymbolsCache::saveCacheStream(QDataStream& stream)
231 {
232  klfDataStreamWriteHeader(stream, "KLATEXFORMULA_SYMBOLS_PIXMAP_CACHE");
233  // stream is now ready to be written
234  stream << cache;
235  flag_modified = false;
236  return 0;
237 }
238 
240 {
241  klfDbg("sym.symbol="<<sym.symbol<<" fromCacheOnly="<<fromcacheonly) ;
242 
243  if (cache.contains(sym)) {
244  klfDbg("Found symbol in cache! pixmap is null="<<cache[sym].isNull()<<"; sym.preamble="<<sym.preamble.join(";"));
245  return cache[sym];
246  }
247 
248  if (fromcacheonly) {
249  // if we weren't able to load it from cache, show failed icon
250  return QPixmap(":/pics/badsym.png");
251  }
252 
253  {
254  KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME+"/clean cache duplicate test") ;
255  // clean cache: make sure there are no two duplicate symbols (this is for the popup hint parser,
256  // so that it doesn't detect old symbols in the cache)
257  // This is done only if fromcache is false, so as to perform the check only on first pass
258  // when generating the symbol cache.
260  while (it != cache.end()) {
261  klfDbg("Testing symbol "<<it.key().symbol<<",preamble="<<it.key().preamble.join(",")
262  << "for being a duplicate of "<<sym.symbol);
263  if (it.key().symbol == sym.symbol) {
264  klfDbg("erasing duplicate.");
265  it = cache.erase(it); // erase old symbol entry
266  } else {
267  ++it;
268  }
269  }
270  }
271 
272  if (sym.hidden) {
273  // special treatment for hidden symbols
274  // insert a QPixmap() into cache and return it
275  klfDbg("symbol is hidden. Assigning NULL pixmap.") ;
276  cache[sym] = QPixmap();
277  return QPixmap();
278  }
279 
280  const float mag = 4.0;
281 
283  in.latex = sym.symbol;
284  in.mathmode = sym.textmode ? "..." : "\\[ ... \\]";
285  in.preamble = sym.preamble.join("\n")+"\n";
286  in.fg_color = qRgb(0,0,0);
287  in.bg_color = qRgba(255,255,255,0); // transparent Bg
288  in.dpi = (int)(mag * 150);
289 
290  backendsettings.epstopdfexec = ""; // don't waste time making PDF, we don't need it
291  backendsettings.tborderoffset = sym.bbexpand.t;
292  backendsettings.rborderoffset = sym.bbexpand.r;
293  backendsettings.bborderoffset = sym.bbexpand.b;
294  backendsettings.lborderoffset = sym.bbexpand.l;
295 
296  KLFBackend::klfOutput out = KLFBackend::getLatexFormula(in, backendsettings);
297 
298  if (out.status != 0) {
299  qWarning()
300  <<KLF_FUNC_NAME
301  <<QString(":ERROR: Can't generate preview for symbol %1 : status %2 !\n\tError: %3\n")
302  .arg(sym.symbol).arg(out.status).arg(out.errorstr);
303  return QPixmap(":/pics/badsym.png");
304  }
305 
306  flag_modified = true;
307 
308  QImage scaled = out.result.scaled((int)(out.result.width() / mag),
309  (int)(out.result.height() / mag),
310  Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
311  QPixmap pix = QPixmap::fromImage(scaled);
312  cache[sym] = pix;
313 
314  klfDbg("Ran getLatexFormula(), got the pixmap. Returning.") ;
315 
316  return pix;
317 }
318 
320  QWidget *parent)
321 {
323 
324  QProgressDialog *pdlg = NULL;
325 
326  if (userfeedback) {
327  pdlg = new QProgressDialog(QObject::tr("Please wait while generating symbol previews ... "),
328  QObject::tr("Skip"), 0, list.size()-1, parent);
331  // pdlg->setMinimumDuration(15000);
332  pdlg->setWindowModality(Qt::WindowModal);
333  pdlg->setModal(true);
334  pdlg->setValue(0);
335  }
336 
337  for (int i = 0; i < list.size(); ++i) {
338  if (userfeedback) {
339  // get events for cancel button (for example)
340  qApp->processEvents();
341  if (pdlg->wasCanceled()) {
342  delete pdlg;
343  return 1;
344  }
345  pdlg->setValue(i);
346  }
347  getPixmap(list[i], false);
348  }
349 
350  if (userfeedback) {
351  delete pdlg;
352  }
353 
354  return 0;
355 };
356 
357 
358 
360 {
361  backendsettings = settings;
362 }
363 
365 {
367  it != cache.end(); ++it) {
368  if (it.key().symbol == symbolCode)
369  return it.key();
370  }
371  return KLFLatexSymbol();
372 }
373 
375 {
376  QStringList l;
378  it != cache.end(); ++it)
379  l << it.key().symbol;
380  return l;
381 }
382 
384 {
385  KLFLatexSymbol sym = findSymbol(symbolCode);
386  if (sym.symbol.isEmpty()) {
387  // invalid symbol
388  qWarning()<<KLF_FUNC_NAME<<": Can't find symbol "<<symbolCode<<".";
389  return QPixmap();
390  }
391  // return the pixmap from cache
392  return cache[sym];
393 }
394 
395 
396 
397 
398 
399 
400 
401 // private
402 int KLFLatexSymbolsCache::loadCacheFrom(const QString& fname, int version)
403 {
404  QFile f(fname);
405  if ( ! f.open(QIODevice::ReadOnly) ) {
406  klfDbg("Failed to open "<<fname) ;
407  return -1;
408  }
409  QDataStream ds(&f);
410  if (version >= 0)
411  ds.setVersion(version);
412  int r = loadCacheStream(ds);
413  return r;
414 }
415 
416 
417 // static
419 {
420  if (staticCache == NULL) {
421  staticCache = new KLFLatexSymbolsCache;
422  }
423  return staticCache;
424 }
425 // static
427 {
428  if (staticCache->cacheNeedsSave()) {
430  QFile f(s);
431  if ( ! f.open(QIODevice::WriteOnly) ) {
432  qWarning() << KLF_FUNC_NAME<< "Can't save cache to file "<< s << "!";
433  return;
434  }
435  QDataStream ds(&f);
436  ds.setVersion(QDataStream::Qt_4_4);
437  staticCache->saveCacheStream(ds);
438  klfDbg("Saved cache to file "<<s);
439  }
440 }
441 
442 
443 
444 
445 // -----------------------------------------------------------
446 
447 
448 
449 
450 
452  : QScrollArea(parent), _category(category)
453 {
454  mFrame = new QWidget(this);
455 
456  setWidgetResizable(true);
457 
458  // mFrame->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
459  // mFrame->setFrameShadow(QFrame::Sunken);
460  // mFrame->setFrameShape(QFrame::Box);
461  mFrame->setObjectName("frmSymbolList");
462  // mFrame->setFrameShadow(QFrame::Plain);
463  // mFrame->setFrameShape(QFrame::NoFrame);
464  // mFrame->setMidLineWidth(0);
465  // mFrame->setLineWidth(0);
466 
467  mLayout = 0;
468  mSpacerItem = 0;
469 
470  setWidget(mFrame);
471 }
472 
474 {
475  _symbols.clear();
476  appendSymbolList(symbols);
477 }
479 {
480  // filter out hidden symbols
481  int k;
482  for (k = 0; k < symbols.size(); ++k)
483  if ( ! symbols[k].hidden )
484  _symbols.append(symbols[k]);
485 }
486 
488 {
490 #ifdef Q_WS_MAC
491  QStyle *myStyle = new QPlastiqueStyle;
492  QPalette pal = palette();
493  pal.setColor(QPalette::Window, QColor(206,207,233));
494  pal.setColor(QPalette::Base, QColor(206,207,233));
495  pal.setColor(QPalette::Button, QColor(206,207,233));
496 #endif
497  mLayout = new QGridLayout(mFrame);
498  int i;
499  for (i = 0; i < _symbols.size(); ++i) {
501  KLFPixmapButton *btn = new KLFPixmapButton(p, mFrame);
502 #ifdef Q_WS_MAC
503  btn->setStyle(myStyle);
504  btn->setPalette(pal);
505 #endif
506  btn->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
507  btn->setProperty("symbol", QVariant::fromValue<int>(i));
508  btn->setProperty("gridpos", QPoint(-1,-1));
509  btn->setProperty("gridcolspan", -1);
510  btn->setProperty("myWidth", p.width() + 4);
511  QString tooltiptext =
512  "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\""
513  " \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
514  "<html><head><meta name=\"qrichtext\" content=\"1\" />"
515  "<style type=\"text/css\">\n"
516  "p { white-space: pre-wrap; padding: 0px; margin: 0px 0px 2px 0px; }\n"
517  "pre { padding: 0px; margin: 0px 0px 2px 0px; }\n"
518  "</style>"
519  "</head>"
520  "<body>\n"
521  "<p style=\"white-space: pre\">"+tr("LaTeX code:")+" <b><tt>"+_symbols[i].symbol+"</tt></b>"+
522  (_symbols[i].textmode?tr(" [in text mode]"):QString(""))+
523  +"</p>";
524  if (_symbols[i].preamble.size())
525  tooltiptext += "<p>"+tr("Requires:")+"<b><pre>" +
526  _symbols[i].preamble.join("\n")+"</pre></b></p>";
527  tooltiptext += "</body></html>";
528  btn->setToolTip(tooltiptext);
529  //klfDbg("tooltip text is "<<tooltiptext);
530  connect(btn, SIGNAL(clicked()), this, SLOT(slotSymbolActivated()));
531  mSymbols.append(btn);
532  }
533  mSpacerItem = new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding);
534  recalcLayout();
535 }
536 
538 {
539  int row = 0, col = 0, colspan;
540  int n = klfconfig.UI.symbolsPerLine;
541  int quantawidth = 55; // hard-coded here
542  // printf("DEBUG: n=%d, quantawidth=%d\n", n, quantawidth);
543  int i;
544  // now add them all again as needed
545  for (i = 0; i < mSymbols.size(); ++i) {
546  colspan = 1 + mSymbols[i]->property("myWidth").toInt() / quantawidth;
547  if (colspan < 1)
548  colspan = 1;
549 
550  if (colspan > n)
551  colspan = n;
552  if (col + colspan > n) {
553  row++;
554  col = 0;
555  }
556  if (mSymbols[i]->property("gridpos") != QPoint(row, col) ||
557  mSymbols[i]->property("gridcolspan") != colspan) {
558  // printf("DEBUG: %d: setting to (%d,%d)+(1,%d)\n", i, row, col, colspan);
559  mSymbols[i]->setProperty("gridpos", QPoint(row, col));
560  mSymbols[i]->setProperty("gridcolspan", colspan);
561  mLayout->removeWidget(mSymbols[i]);
562  mLayout->addWidget(mSymbols[i], row, col, 1, colspan);
563  }
564  col += colspan;
565  if (col >= n) {
566  row++;
567  col = 0;
568  }
569  }
570  // remove spacer and add it again
571  mLayout->removeItem(mSpacerItem);
572  mLayout->addItem(mSpacerItem, row+1, 0);
573 
574  setMinimumWidth(mFrame->sizeHint().width() + verticalScrollBar()->width() + 2);
575 }
576 
577 
579 {
580  QObject *s = sender();
581  int i = s->property("symbol").toInt();
582  if (i < 0 || i >= _symbols.size())
583  qWarning()<<KLF_FUNC_NAME<<": Inavlid symbol index "<<i;
584  else
585  emit symbolActivated(_symbols[i]);
586 }
587 
588 
590 {
591  // remember: SearchIterator==int
592  if (pos < 0 || pos >= mSymbols.size())
593  return false;
594 
595  int symIndex = mSymbols[pos]->property("symbol").toInt();
596  if (symIndex < 0 || symIndex >= _symbols.size()) {
597  qWarning()<<KLF_FUNC_NAME<<": Inavlid symbol index "<<symIndex;
598  return false;
599  }
600 
601  // (X)Emacs-style: presence of capital letter triggers case sensitive search
602  Qt::CaseSensitivity cs = (queryString.contains(QRegExp("[A-Z]")) ? Qt::CaseSensitive : Qt::CaseInsensitive) ;
603 
604  if ( _symbols[symIndex].symbol.contains(queryString, cs) ||
605  _symbols[symIndex].preamble.contains(queryString, cs) ) {
606  klfDbg("found match at "<<symIndex<<": "<<_symbols[symIndex].symbol) ;
607  return true;
608  }
609  return false;
610 }
611 
613 {
614  klfDbg("result is "<<result<<" valid="<<(result<mSymbols.size())) ;
615 
616  highlightSearchMatches(result);
617 }
619 {
621  highlightSearchMatches(-1);
622  // setFocus();
623 }
624 
625 void KLFLatexSymbolsView::highlightSearchMatches(int currentMatch)
626 {
627  QString stylesheets[] = {
628  // don't affect tooltips: give KLFPixmapButton { } scopes
629  "",
630  "KLFPixmapButton { background-color: rgb(180,180,255); }",
631  "KLFPixmapButton { background-color: rgb(0,0,255); }"
632  };
633 
634  if (currentMatch == -1) {
635  // abort search
636  stylesheets[0] = stylesheets[1] = stylesheets[2] = QString();
637  }
638  int k;
639  for (k = 0; k < mSymbols.size(); ++k) {
640  int which = 0;
641  if (k == currentMatch)
642  which = 2;
643  else if (searchIterMatches(k, searchQueryString()))
644  which = 1;
645  mSymbols[k]->setStyleSheet(stylesheets[which]);
646  }
647  if (currentMatch >= 0 && currentMatch < mSymbols.size())
648  ensureWidgetVisible(mSymbols[currentMatch]);
649 }
650 
651 
652 
653 
654 
656  : QWidget(
657 #if defined(Q_OS_WIN32)
658  0 /* parent */
659 #else
660  parent /* 0 */
661 #endif
662  , /*Qt::Tool*/ Qt::Window /*0*/)
663 {
665 
666  u = new Ui::KLFLatexSymbols;
667  u->setupUi(this);
668  setAttribute(Qt::WA_StyledBackground);
669 
670  // add our search bar
671  pSearchBar = new KLFSearchBar(this);
672  KLF_DEBUG_ASSIGN_REF_INSTANCE(pSearchBar, "latexsymbols-searchbar") ;
673  pSearchBar->setShowOverlayMode(true);
674  pSearchBar->registerShortcuts(this);
675  pSearchBar->setSearchText("");
676  pSearchBar->setShowHideButton(true);
677  connect(pSearchBar, SIGNAL(escapePressed()), pSearchBar, SLOT(hide()));
678 
679  klfDbg("prepared search bar.") ;
680 
682 
683  // read our config and create the UI
684  read_symbols_create_ui();
685 
686  slotShowCategory(0);
687 
688  QFont f = u->cbxCategory->font();
689  int ps = f.pointSize();
690  if (ps < 8)
691  ps = QFontInfo(f).pointSize();
692  f.setPointSize(ps+1);
693  u->cbxCategory->setFont(f);
694 
695  connect(u->cbxCategory, SIGNAL(highlighted(int)), this, SLOT(slotShowCategory(int)));
696  connect(u->cbxCategory, SIGNAL(activated(int)), this, SLOT(slotShowCategory(int)));
697  connect(u->btnClose, SIGNAL(clicked()), this, SLOT(close()));
698 }
699 
700 void KLFLatexSymbols::retranslateUi(bool alsoBaseUi)
701 {
702  if (alsoBaseUi)
703  u->retranslateUi(this);
704 }
705 
707 {
709 }
710 
711 void KLFLatexSymbols::read_symbols_create_ui()
712 {
713  klfDbgT("called.") ;
714 
715  // create our UI
716  u->cbxCategory->clear();
717  QGridLayout *lytstk = new QGridLayout(u->frmStackContainer);
718  stkViews = new QStackedWidget(u->frmStackContainer);
719  lytstk->addWidget(stkViews, 0, 0);
720 
721  mViews.clear();
722 
723  // find collection of XML files
724  QStringList fxmllist;
725  // in the following directories
726  QStringList fxmldirs;
727  fxmldirs << klfconfig.homeConfigDir + "/conf/latexsymbols.d/"
728  << klfconfig.globalShareDir + "/conf/latexsymbols.d/"
729  << ":/conf/latexsymbols.d/";
730 
731  klfDbgT("starting to collect XML files from dirs "<<fxmldirs) ;
732 
733  // collect all XML files
734  int k, j;
735  for (k = 0; k < fxmldirs.size(); ++k) {
736  QDir fxmldir(fxmldirs[k]);
737  QStringList xmllist = fxmldir.entryList(QStringList()<<"*.xml", QDir::Files);
738  for (j = 0; j < xmllist.size(); ++j)
739  fxmllist << fxmldir.absoluteFilePath(xmllist[j]);
740  }
741  klfDbgT("files collected: "<<fxmllist) ;
742  if (fxmllist.isEmpty()) {
743  // copy legacy XML file into the home latexsymbols.d directory
744  QDir("/").mkpath(klfconfig.homeConfigDir+"/conf/latexsymbols.d");
745  if (QFile::exists(klfconfig.homeConfigDir+"/latexsymbols.xml")) {
746  QFile::copy(klfconfig.homeConfigDir+"/latexsymbols.xml",
747  klfconfig.homeConfigDir+"/conf/latexsymbols.d/mylatexsymbols.xml");
748  fxmllist << klfconfig.homeConfigDir+"/conf/latexsymbols.d/mylatexsymbols.xml";
749  } else {
750  QFile::copy(":/data/latexsymbols.xml",
751  klfconfig.homeConfigDir+"/conf/latexsymbols.d/defaultlatexsymbols.xml");
752  fxmllist << klfconfig.homeConfigDir+"/conf/latexsymbols.d/defaultlatexsymbols.xml";
753  }
754  }
755 
756  klfDbgT("got xml files, ensured not empty; fxmllist="<<fxmllist) ;
757 
758  // this will be a full list of symbols to feed to the cache
759  QList<KLFLatexSymbol> allsymbols;
760 
761  // same indexes as in mViews[]
762  QStringList categoryTitleLangs;
763 
764  // now read the file list
765  for (k = 0; k < fxmllist.size(); ++k) {
766  KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME+"/fxmllist["+('0'+k)+"]");
767  klfDbg("reading XML file="<<fxmllist[k]);
768 
769  QString fn = fxmllist[k];
770  QFile file(fn);
771  if ( ! file.open(QIODevice::ReadOnly) ) {
772  qWarning()<<KLF_FUNC_NAME<<": Error: Can't open latex symbols XML file "<<fn<<": "<<file.errorString()<<"!";
773  continue;
774  }
775 
776  QDomDocument doc("latexsymbols");
777  QString errMsg; int errLine, errCol;
778  bool r = doc.setContent(&file, false, &errMsg, &errLine, &errCol);
779  if (!r) {
780  qWarning()<<KLF_FUNC_NAME<<": Error parsing file "<<fn<<": "<<errMsg<<" at line "<<errLine<<", col "<<errCol;
781  continue;
782  }
783  file.close();
784 
785  QDomElement root = doc.documentElement();
786  if (root.nodeName() != "latexsymbollist") {
787  qWarning("%s: Error parsing XML for latex symbols from file `%s': unexpected root tag `%s'.\n", KLF_FUNC_NAME,
788  qPrintable(fn), qPrintable(root.nodeName()));
789  continue;
790  }
791 
792  QDomNode n;
793  for (n = root.firstChild(); ! n.isNull(); n = n.nextSibling()) {
794  QDomElement e = n.toElement(); // try to convert the node to an element.
795  if ( e.isNull() || n.nodeType() != QDomNode::ElementNode )
796  continue;
797  if ( e.nodeName() != "category" ) {
798  qWarning("WARNING in parsing XML : ignoring unexpected tag `%s'!\n",
799  qPrintable(e.nodeName()));
800  continue;
801  }
802  // read category
803  QString heading = e.attribute("name");
804  QString categoryTitle;
805  // xml:lang attribute for category title is obsolete, we use now Qt-linguist translated value...
806  QString curCategoryTitleLang;
808  QDomNode esym;
809  for (esym = e.firstChild(); ! esym.isNull(); esym = esym.nextSibling() ) {
810  if ( esym.isNull() || esym.nodeType() != QDomNode::ElementNode )
811  continue;
812  QDomElement eesym = esym.toElement();
813  klfDbg("read element "<<esym.nodeName());
814  if ( eesym.nodeName() == "category-title" ) {
815  // xml:lang attribute for category title is obsolete, we use now Qt-linguist translated value...
816  QString lang = eesym.hasAttribute("xml:lang") ? eesym.attribute("xml:lang") : QString() ;
817  klfDbg("<category-title>: lang="<<lang<<"; hasAttribute(xml:lang)="<<eesym.hasAttribute("xml:lang")
818  <<"; current category-title="<<categoryTitle<<",lang="<<curCategoryTitleLang) ;
819  if (categoryTitle.isEmpty()) {
820  // no category title yet
821  if (lang.isEmpty() || lang.startsWith(klfconfig.UI.locale) || klfconfig.UI.locale.startsWith(lang)) {
822  // correct locale
823  categoryTitle = qApp->translate("xmltr_latexsymbols", eesym.text().toUtf8().constData(),
824  "[[tag: <category-title>]]", QCoreApplication::UnicodeUTF8);
825  curCategoryTitleLang = lang;
826  }
827  // otherwise skip this tag
828  } else {
829  // see if this locale is correct and more specific
830  if ( (lang.startsWith(klfconfig.UI.locale) || klfconfig.UI.locale.startsWith(lang)) &&
831  (curCategoryTitleLang.isEmpty() || lang.startsWith(curCategoryTitleLang) ) ) {
832  // then keep it and replace the other
833  categoryTitle = eesym.text();
834  curCategoryTitleLang = lang;
835  }
836  // otherwise skip this tag
837  }
838  continue;
839  }
840  if ( esym.nodeName() != "sym" ) {
841  qWarning("%s: WARNING in parsing XML : ignoring unexpected tag `%s' in category `%s'!\n",
842  KLF_FUNC_NAME, qPrintable(esym.nodeName()), qPrintable(heading));
843  continue;
844  }
845  // read symbol
846  KLFLatexSymbol sym(eesym);
847  l.append(sym);
848  allsymbols.append(sym);
849  }
850  // and add this category, or append to existing category
851  KLFLatexSymbolsView * view = NULL;
852  for (j = 0; j < mViews.size(); ++j) {
853  if (mViews[j]->category() == heading) {
854  view = mViews[j];
855  break;
856  }
857  }
858  if (view == NULL) {
859  // category does not yet exist
860  view = new KLFLatexSymbolsView(heading, stkViews);
861  connect(view, SIGNAL(symbolActivated(const KLFLatexSymbol&)),
862  this, SIGNAL(insertSymbol(const KLFLatexSymbol&)));
863  mViews.append(view);
864  stkViews->addWidget(view);
865  if (categoryTitle.isEmpty())
866  categoryTitle = heading;
867  u->cbxCategory->addItem(categoryTitle, heading);
868  categoryTitleLangs << curCategoryTitleLang;
869  } else {
870  // possibly update the title if a better translation is available
871  if (!categoryTitle.isEmpty() &&
872  (categoryTitleLangs[j].isEmpty() || curCategoryTitleLang.startsWith(categoryTitleLangs[j]))) {
873  // update the title
874  u->cbxCategory->setItemText(j, categoryTitle);
875  } else {
876  // keep old title
877  }
878  }
879 
880  view->appendSymbolList(l);
881  } // iterate over categories in XML file
882  } // iterate over XML files
883 
884  // pre-cache all our symbols
885  KLFLatexSymbolsCache::theCache()->precacheList(allsymbols, true, this);
886 
887  int i;
888  for (i = 0; i < mViews.size(); ++i) {
889  mViews[i]->buildDisplay();
890  }
891 
892 }
893 
895 {
897 
898  // called by combobox
899  stkViews->setCurrentIndex(c);
900 
901  klfDbg("current index="<<c) ;
902 
903  QWidget * w = stkViews->currentWidget();
904  KLFSearchable * target = NULL;
905  if (w != NULL) {
906  KLFLatexSymbolsView *view = qobject_cast<KLFLatexSymbolsView*>(w);
907  if (view != NULL)
908  target = view;
909  }
910  pSearchBar->setSearchTarget(target);
911 }
912 
914 {
915  e->accept();
916 }
917 
919 {
921 }
922 
923 
925 {
926  if (e->type() == QEvent::Polish) {
927  u->cbxCategory->setMinimumHeight(u->cbxCategory->sizeHint().height()+5);
928  }
929  if (e->type() == QEvent::KeyPress) {
930  QKeyEvent *ke = (QKeyEvent*)e;
931  if (ke->key() == Qt::Key_F7 && ke->modifiers() == 0) {
932  hide();
933  e->accept();
934  return true;
935  }
936  }
937  return QWidget::event(e);
938 }
939 
QDataStream & operator<<(QDataStream &stream, const KLFLatexSymbol &s)
void setSymbolList(const QList< KLFLatexSymbol > &symbols)
fromAscii(const char *str, int size=-1)
elementsByTagName(const QString &tagname)
setPointSize(int pointSize)
setWidget(QWidget *widget)
void slotShowCategory(int cat)
QString locale
When setting this, don&#39;t forget to call QLocale::setDefault().
Definition: klfconfig.h:177
QDataStream & operator>>(QDataStream &stream, KLFLatexSymbol &s)
erase(iterator pos)
QList< KLFLatexSymbol > _symbols
QString searchQueryString() const
setColor(ColorGroup group, ColorRole role, const QColor &color)
addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment=0)
static KLFLatexSymbolsCache * theCache()
#define klfDbgT(streamableItems)
QStringList preamble
KLFConfig klfconfig
Definition: klfconfig.cpp:88
struct KLFConfig::@1 UI
void symbolActivated(const KLFLatexSymbol &symb)
void retranslateUi(bool alsoBaseUi=true)
static void saveTheCache()
QStackedWidget * stkViews
QPixmap findSymbolPixmap(const QString &symbolCode)
virtual void searchPerformed(const SearchIterator &result)
QList< KLFLatexSymbolsView * > mViews
#define klfDbg(streamableItems)
KLFLatexSymbolsView(const QString &category, QWidget *parent)
setAttribute(Qt::WidgetAttribute attribute, bool on=true)
fromImage(const QImage &image, Qt::ImageConversionFlags flags=Qt::AutoColor)
#define KLF_DEBUG_BLOCK(msg)
QStringList symbolCodeList()
join(const QString &separator)
void appendSymbolList(const QList< KLFLatexSymbol > &symbols)
tr(const char *sourceText, const char *comment=0, int n=-1)
virtual void setSearchTarget(KLFSearchable *object)
copy(const QString &newName)
void showEvent(QShowEvent *ev)
int precacheList(const QList< KLFLatexSymbol > &list, bool userfeedback, QWidget *parent=NULL)
showEvent(QShowEvent *event)
append(const T &value)
property(const char *name)
int symbolsPerLine
Definition: klfconfig.h:185
hasAttribute(const QString &name)
QPixmap getPixmap(const KLFLatexSymbol &sym, bool fromcacheonly=true)
KLFLatexSymbol findSymbol(const QString &symbolCode)
void closeEvent(QCloseEvent *ev)
entryList(const QStringList &nameFilters, Filters filters=NoFilter, SortFlags sort=NoSort)
#define KLF_DEBUG_ASSIGN_REF_INSTANCE(object, ref_instance)
KLFLatexSymbols(QWidget *parent, const KLFBackend::klfSettings &baseSettings)
unsigned long fg_color
startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive)
static QString relcachefile()
virtual void searchAbort()
unsigned long bg_color
bool event(QEvent *event)
virtual void searchAbort()
open(OpenMode mode)
virtual void setSearchText(const QString &text)
static QString __rel_cache_file
#define KLF_DEBUG_TIME_BLOCK(msg)
void setShowHideButton(bool showHideButton)
setVersion(int v)
ensureWidgetVisible(QWidget *childWidget, int xmargin=50, int ymargin=50)
#define KLF_FUNC_NAME
contains(const QString &str, Qt::CaseSensitivity cs=Qt::CaseSensitive)
#define KLF_DATA_STREAM_APP_VERSION
Current datastream compatibility klatexformula version.
Definition: klfmain.h:280
contains(const T &value)
key(const T &value)
QString homeConfigDir
Definition: klfconfig.h:151
struct KLFLatexSymbol::BBOffset bbexpand
KLF_EXPORT bool operator<(const KLFLatexSymbol &a, const KLFLatexSymbol &b)
virtual bool searchIterMatches(const SearchIterator &pos, const QString &queryString)
scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode=Qt::IgnoreAspectRatio, Qt::TransformationMode transformMode=Qt::FastTransformation)
void setShowOverlayMode(bool showOverlayMode)
addItem(QLayoutItem *item, int row, int column, int rowSpan=1, int columnSpan=1, Qt::Alignment alignment=0)
at(int position)
KLF_EXPORT bool operator==(const KLFLatexSymbol &a, const KLFLatexSymbol &b)
absoluteFilePath(const QString &fileName)
void setBackendSettings(const KLFBackend::klfSettings &settings)
QString globalShareDir
Definition: klfconfig.h:152
KLF_EXPORT void klfDataStreamWriteHeader(QDataStream &stream, const QString headermagic)
Definition: klfmain.cpp:529
virtual void registerShortcuts(QWidget *parent)
addWidget(QWidget *widget)
event(QEvent *event)
KLF_EXPORT bool klfDataStreamReadHeader(QDataStream &stream, const QStringList possibleHeaders, QString *readHeader, QString *readCompatKLFVersion)
Definition: klfmain.cpp:546
static klfOutput getLatexFormula(const klfInput &in, const klfSettings &settings)
pointSize()
mkpath(const QString &dirPath)
void insertSymbol(const KLFLatexSymbol &symb)
setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg=0, int *errorLine=0, int *errorColumn=0)
at(int index)
attribute(const QString &name, const QString &defValue=QString()

Generated by doxygen 1.8.11