00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef KLFMAINWIN_P_H
00025 #define KLFMAINWIN_P_H
00026
00027
00033 #include <QDialog>
00034 #include <QFile>
00035 #include <QString>
00036 #include <QByteArray>
00037 #include <QLabel>
00038 #include <QImageReader>
00039 #include <QBuffer>
00040 #include <QFileInfo>
00041 #include <QMessageBox>
00042
00043 #include <klfutil.h>
00044 #include "klflibview.h"
00045 #include "klfmain.h"
00046 #include "klfsettings.h"
00047
00048 #include "klfmainwin.h"
00049
00050 #include <ui_klfaboutdialog.h>
00051 #include <ui_klfwhatsnewdialog.h>
00052
00054 class KLFHelpDialogCommon
00055 {
00056 public:
00057 KLFHelpDialogCommon(const QString& baseFName) : pBaseFName(baseFName) { }
00058 virtual ~KLFHelpDialogCommon() { }
00059
00060 virtual void addExtraText(const QString& htmlSnipplet)
00061 {
00062 pHtmlExtraSnipplets << htmlSnipplet;
00063 }
00064
00065 virtual QString getFullHtml()
00066 {
00067 QString html;
00068 QString fn = klfFindTranslatedDataFile(":/data/"+pBaseFName, ".html");
00069
00070 QFile f(fn);
00071 f.open(QIODevice::ReadOnly);
00072 html = QString::fromUtf8(f.readAll());
00073
00074 klfDbg( "read from file="<<fn<<" the HTML code=\n"<<html ) ;
00075
00076 const QString marker = QLatin1String("<!--KLF_MARKER_INSERT_SPOT-->");
00077 int k;
00078 for (k = 0; k < pHtmlExtraSnipplets.size(); ++k)
00079 html.replace(marker, pHtmlExtraSnipplets[k]+"\n"+marker);
00080
00081 klfDbg( "new HTML is:\n"<<html ) ;
00082
00083
00084 html.replace("<!--KLF_VERSION-->", KLF_VERSION_STRING);
00085
00086 return html;
00087 }
00088
00089 protected:
00090 QString pBaseFName;
00091 QStringList pHtmlExtraSnipplets;
00092 };
00093
00094
00096 class KLFAboutDialog : public QDialog, public KLFHelpDialogCommon
00097 {
00098 Q_OBJECT
00099 signals:
00100 void linkActivated(const QUrl&);
00101 public:
00102 KLFAboutDialog(QWidget *parent) : QDialog(parent), KLFHelpDialogCommon("about")
00103 {
00104 u = new Ui::KLFAboutDialog;
00105 u->setupUi(this);
00106
00107 connect(u->txtDisplay, SIGNAL(anchorClicked(const QUrl&)),
00108 this, SIGNAL(linkActivated(const QUrl&)));
00109 }
00110 virtual ~KLFAboutDialog() { }
00111
00112 virtual void show()
00113 {
00114 u->txtDisplay->setHtml(getFullHtml());
00115 QDialog::show();
00116
00117 setStyleSheet(styleSheet());
00118 }
00119
00120 private:
00121 Ui::KLFAboutDialog *u;
00122 };
00123
00124
00126 class KLFWhatsNewDialog : public QDialog, public KLFHelpDialogCommon
00127 {
00128 Q_OBJECT
00129 signals:
00130 void linkActivated(const QUrl&);
00131 public:
00132 KLFWhatsNewDialog(QWidget *parent)
00133 : QDialog(parent),
00134 KLFHelpDialogCommon(QString("whats-new-%1.%2").arg(klfVersionMaj()).arg(klfVersionMin()))
00135 {
00136 u = new Ui::KLFWhatsNewDialog;
00137 u->setupUi(this);
00138
00139 connect(u->txtDisplay, SIGNAL(anchorClicked(const QUrl&)),
00140 this, SIGNAL(linkActivated(const QUrl&)));
00141 }
00142 virtual ~KLFWhatsNewDialog() { }
00143
00144 virtual void show()
00145 {
00146 u->txtDisplay->setHtml(getFullHtml());
00147 QDialog::show();
00148
00149 setStyleSheet(styleSheet());
00150 }
00151
00152 private:
00153 Ui::KLFWhatsNewDialog *u;
00154 };
00155
00156
00157
00159 class KLFMainWinPopup : public QLabel
00160 {
00161 Q_OBJECT
00162 public:
00163 KLFMainWinPopup(KLFMainWin *mainwin)
00164 : QLabel(mainwin, Qt::Window|Qt::FramelessWindowHint|Qt::CustomizeWindowHint|
00165 Qt::WindowStaysOnTopHint|Qt::X11BypassWindowManagerHint)
00166 {
00167 setObjectName("KLFMainWinPopup");
00168 setFocusPolicy(Qt::NoFocus);
00169 QWidget *frmMain = mainwin->findChild<QWidget*>("frmMain");
00170 if (frmMain)
00171 setGeometry(QRect(mainwin->geometry().topLeft()+QPoint(25,mainwin->height()*2/3),
00172 QSize(frmMain->width()+15, 0)));
00173 setAttribute(Qt::WA_ShowWithoutActivating, true);
00174 setProperty("klfTopLevelWidget", QVariant(true));
00175 setAttribute(Qt::WA_StyledBackground, true);
00176 setStyleSheet(mainwin->window()->styleSheet());
00177 setMargin(0);
00178 QFont f = font();
00179 f.setPointSize(QFontInfo(f).pointSize() - 1);
00180 setFont(f);
00181 setWordWrap(true);
00182
00183 connect(this, SIGNAL(linkActivated(const QString&)),
00184 this, SLOT(internalLinkActivated(const QString&)));
00185 connect(this, SIGNAL(linkActivated(const QUrl&)),
00186 mainwin, SLOT(helpLinkAction(const QUrl&)));
00187 }
00188
00189 virtual ~KLFMainWinPopup() { }
00190
00191 bool hasMessages() { return (bool)msgKeys.size(); }
00192
00193 QStringList messageKeys() { return msgKeys; }
00194
00195 signals:
00196 void linkActivated(const QUrl& url);
00197
00198 public slots:
00199
00203 void addMessage(const QString& msgKey, const QString& msgText)
00204 {
00205 klfDbg("adding message "<<msgKey<<" -> "<<msgText);
00206 msgKeys << msgKey;
00207 messages << ("<p>"+msgText+"</p>");
00208 updateText();
00209 }
00210
00211 void removeMessage(const QString& msgKey)
00212 {
00213 int i = msgKeys.indexOf(msgKey);
00214 if (i < 0)
00215 return;
00216 msgKeys.removeAt(i);
00217 messages.removeAt(i);
00218 updateText();
00219 }
00220
00221 void show()
00222 {
00223 QLabel::show();
00224 setStyleSheet(styleSheet());
00225 }
00226
00227 private slots:
00228 void internalLinkActivated(const QString& url)
00229 {
00230 emit linkActivated(QUrl::fromEncoded(url.toLatin1()));
00231 }
00232
00233 void updateText()
00234 {
00235 setText("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\""
00236 " \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
00237 "<html><head><meta name=\"qrichtext\" content=\"1\" />"
00238 "<style type=\"text/css\">\n"
00239 "body { margin: 2px 10px; }\n"
00240 "p { white-space: pre-wrap; padding: 0px; margin: 0px 0px 2px 0px; }\n"
00241 "a, a:link { text-decoration: underline; color: #0000af }\n"
00242 "a:hover { color: #0000ff }\n"
00243 "a:active { color: #ff0000 }\n"
00244 "}\n"
00245 "</style>"
00246 "</head>"
00247 "<body>\n"
00248 + messages.join("\n") +
00249 "<p style=\"margin-top: 5px\">"
00250 "<a href=\"klfaction:/popup?acceptAll\">"+tr("Accept [<b>Alt-Enter</b>]")+"</a> | "+
00251 " <a href=\"klfaction:/popup_close\">"+tr("Close [<b>Esc</b>]")+"</a> | " +
00252 " <a href=\"klfaction:/popup?configDontShow\">"+tr("Don't Show Again")+"</a></p>"+
00253 "</body></html>" );
00254 resize(width(), sizeHint().height());
00255 }
00256
00257 private:
00258 QStringList msgKeys;
00259 QStringList messages;
00260 };
00261
00262
00263
00264
00265
00266
00267
00268
00269 class KLFBasicDataOpener : public QObject, public KLFAbstractDataOpener
00270 {
00271 Q_OBJECT
00272 public:
00273 KLFBasicDataOpener(KLFMainWin *mainwin) : QObject(mainwin), KLFAbstractDataOpener(mainwin) { }
00274 virtual ~KLFBasicDataOpener() { }
00275
00276 virtual QStringList supportedMimeTypes()
00277 {
00278 QStringList types;
00279 types << "image/png"
00280 << "image/jpeg"
00281 << "text/uri-list"
00282 << "application/x-klf-libentries"
00283 << "application/x-klatexformula"
00284 << "application/x-klatexformula-db" ;
00285 int k;
00286 QList<QByteArray> fmts = QImageReader::supportedImageFormats();
00287 for (k = 0; k < fmts.size(); ++k) {
00288 types << "image/"+fmts[k].toLower();
00289 types << "image/x-"+fmts[k].toLower();
00290 }
00291 klfDbg("mime types: "<<types) ;
00292 return types;
00293 }
00294
00295 virtual bool canOpenFile(const QString& file)
00296 {
00297 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00298 klfDbg("file="<<file) ;
00299
00300 QFile f(file);
00301 bool r = f.open(QIODevice::ReadOnly);
00302 if (!r) {
00303 klfDbg(" ... file cannot be accessed.") ;
00304 return false;
00305 }
00306 bool isimage;
00307 if (isKlfImage(&f, &isimage)) {
00308 klfDbg(" ... is KLF-saved image.") ;
00309 return true;
00310 }
00311 if (isimage) {
00312 klfDbg(" ... is a non-KLF image.") ;
00313 return false;
00314 }
00315
00316 QString libscheme = KLFLibBasicWidgetFactory::guessLocalFileScheme(file);
00317 if (!libscheme.isEmpty()) {
00318 klfDbg(" ... libscheme="<<libscheme) ;
00319 return true;
00320 }
00321
00322 klfDbg(" ... not recognized.") ;
00323 return false;
00324 }
00325
00326 virtual bool canOpenData(const QByteArray& data)
00327 {
00328 QBuffer buf;
00329 buf.setData(data);
00330 buf.open(QIODevice::ReadOnly);
00331 bool isimg = false;
00332 if (isKlfImage(&buf, &isimg))
00333 return true;
00334 if (isimg)
00335 return false;
00336
00337
00338 QDataStream stream(&buf);
00339 stream.setVersion(QDataStream::Qt_4_4);
00340 QString headerstr;
00341 stream >> headerstr;
00342 if (headerstr == QLatin1String("KLF_LIBENTRIES"))
00343 return true;
00344
00345
00346
00347
00348 return false;
00349 }
00350
00351 virtual bool openFile(const QString& file)
00352 {
00353 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00354 klfDbg("file="<<file);
00355 QFileInfo fi(file);
00356 if (!fi.exists() || !fi.isReadable()) {
00357 klfDbg(" ... file is not readable") ;
00358 return false;
00359 }
00360 QString ext = fi.suffix().trimmed().toLower();
00361
00362 {
00363 QFile f(file);
00364 bool r = f.open(QIODevice::ReadOnly);
00365 if (!r) {
00366 klfDbg(" ... file cannot be opened") ;
00367 return false;
00368 }
00369 bool isimage = false;
00370 if (tryOpenImageData(&f, &isimage)) {
00371 klfDbg(" ... loaded image data!") ;
00372 return true;
00373 }
00374 if (isimage) {
00375 klfDbg(" ... is non-KLF image...") ;
00376 return false;
00377 }
00378 }
00379
00380
00381
00382
00383 bool result = mainWin()->openLibFile(file);
00384
00385 klfDbg("mainWin()->openLibFile("<<file<<") returned "<<result) ;
00386 if (result)
00387 return true;
00388
00389
00390 return false;
00391 }
00392
00393 virtual bool openData(const QByteArray& data, const QString& mimetype)
00394 {
00395 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00396 klfDbg("mimetype is "<<mimetype) ;
00397
00398 QBuffer buf;
00399 buf.setData(data);
00400 buf.open(QIODevice::ReadOnly);
00401
00402 if (mimetype == "text/uri-list") {
00403 klfDbg("Opening uri-list") ;
00404 QByteArray line;
00405 QStringList flist;
00406 char sbuf[1024];
00407 qint64 len;
00408 while ((len = buf.readLine(sbuf, sizeof(sbuf))) > 0) {
00409 line = QByteArray(sbuf, len);
00410 line = line.trimmed();
00411 QUrl url = QUrl::fromEncoded(line);
00412 if (url.scheme() != "file") {
00413 qWarning()<<KLF_FUNC_NAME<<": can't open URL "<<url.scheme()<<" (can only open local files)";
00414 continue;
00415 }
00416 flist << klfUrlLocalFilePath(url);
00417 klfDbg("... added file "<<flist.last()) ;
00418 }
00419 if (flist.isEmpty()) {
00420 klfDbg("file list is empty.") ;
00421 return true;
00422 }
00423 return mainWin()->openFiles(flist);
00424 }
00425
00426 bool isimage = false;
00427 if (tryOpenImageData(&buf, &isimage))
00428 return true;
00429 if (isimage)
00430 return false;
00431
00432
00433 if (tryOpenKlfLibEntries(&buf))
00434 return true;
00435
00436
00437
00438
00439 return false;
00440 }
00441
00442 private:
00443 bool prepareImageReader(QImageReader *imagereader, QImage *img, bool *isImage)
00444 {
00445 *isImage = false;
00446 if (!imagereader->canRead()) {
00447 klfDbg("format "<<imagereader->format()<<": canRead() returned FALSE!") ;
00448 return false;
00449 }
00450 *img = imagereader->read();
00451 if (img->isNull()) {
00452 klfDbg("read() returned a null qimage!") ;
00453 return false;
00454 }
00455 *isImage = true;
00456 klfDbg("format: '"<<imagereader->format().constData()<<"': text keys set: "<<img->textKeys()
00457 <<"; error="<<imagereader->error()
00458 <<"; quality="<<imagereader->quality()
00459 <<"; supportsOption(description)="<<imagereader->supportsOption(QImageIOHandler::Description)
00460 <<"; text('AppVersion')="<<img->text("AppVersion")
00461 ) ;
00462 if (!img->text("AppVersion").startsWith("KLatexFormula ") && !img->text("AppVersion").startsWith("KLF ")) {
00463 klfDbg("AppVersion is not set to 'KL[atex]F[ormula] [...]' in image metadata.") ;
00464 return false;
00465 }
00466
00467 return true;
00468 }
00469 bool isKlfImage(QIODevice *device, bool *isImage)
00470 {
00471 QList<QByteArray> formatlist = QImageReader::supportedImageFormats();
00472 int k;
00473 QImage img;
00474 QImageReader imagereader;
00475 for (k = 0; k < formatlist.size(); ++k) {
00476 device->seek(0);
00477 imagereader.setFormat(formatlist[k]);
00478 imagereader.setDevice(device);
00479 if (prepareImageReader(&imagereader, &img, isImage))
00480 return true;
00481 }
00482 return false;
00483 }
00484 bool tryOpenImageData(QIODevice *device, bool *isimage)
00485 {
00486 QList<QByteArray> formatlist = QImageReader::supportedImageFormats();
00487 int k;
00488 QImageReader imagereader;
00489 QImage img;
00490 for (k = 0; k < formatlist.size(); ++k) {
00491 device->seek(0);
00492 imagereader.setFormat(formatlist[k]);
00493 imagereader.setDevice(device);
00494 if (!prepareImageReader(&imagereader, &img, isimage))
00495 continue;
00496
00497
00498 QString latex = img.text("InputLatex");
00499 KLFStyle style;
00500 style.fg_color = read_color(img.text("InputFgColor"));
00501 style.bg_color = read_color(img.text("InputBgColor"));
00502 style.mathmode = img.text("InputMathMode");
00503 style.preamble = img.text("InputPreamble");
00504 style.dpi = img.text("InputDPI").toInt();
00505
00506 mainWin()->slotLoadStyle(style);
00507 mainWin()->slotSetLatex(latex);
00508 return true;
00509 }
00510 return false;
00511 }
00512 unsigned long read_color(const QString& text)
00513 {
00514
00515 QRegExp rx1("\\s*rgba?\\s*\\(\\s*(\\d+),\\s*(\\d+),\\s*(\\d+)(\\s*,\\s*(\\d+))?\\s*\\)\\s*");
00516 if (rx1.exactMatch(text)) {
00517 if (rx1.cap(4).isEmpty())
00518 return qRgb(rx1.cap(1).toInt(), rx1.cap(2).toInt(), rx1.cap(3).toInt());
00519 else
00520 return qRgba(rx1.cap(1).toInt(), rx1.cap(2).toInt(), rx1.cap(3).toInt(), rx1.cap(5).toInt());
00521 }
00522
00523 QColor c(text);
00524 return c.rgba();
00525 }
00526
00527 bool tryOpenKlfLibEntries(QIODevice *dev)
00528 {
00529
00530
00531 QDataStream stream(dev);
00532 stream.setVersion(QDataStream::Qt_4_4);
00533 QString headerstr;
00534 stream >> headerstr;
00535 if (headerstr != QLatin1String("KLF_LIBENTRIES"))
00536 return false;
00537 QVariantMap properties;
00538 KLFLibEntryList entries;
00539 stream >> properties >> entries;
00540 if (entries.size() > 1) {
00541 QMessageBox::critical(mainWin(), tr("Error"),
00542 tr("The data you have request to open contains multiple formulas.\n"
00543 "You may only open one formula into the LaTeX code editor."));
00544 return false;
00545 }
00546 if (entries.size() == 0) {
00547 QMessageBox::critical(mainWin(), tr("Error"),
00548 tr("The data you have request to open contains no formulas."));
00549 return false;
00550 }
00551 mainWin()->restoreFromLibrary(entries[0], KLFLib::RestoreAll);
00552 return true;
00553 }
00554 };
00555
00556
00557
00558
00559
00560
00561 class KLFAddOnDataOpener : public QObject, public KLFAbstractDataOpener
00562 {
00563 Q_OBJECT
00564 public:
00565 KLFAddOnDataOpener(KLFMainWin *mainwin) : QObject(mainwin), KLFAbstractDataOpener(mainwin) { }
00566 virtual ~KLFAddOnDataOpener() { }
00567
00568 virtual QStringList supportedMimeTypes()
00569 {
00570 return QStringList();
00571 }
00572
00573 virtual bool canOpenFile(const QString& file)
00574 {
00575 if (QFileInfo(file).suffix() == "rcc")
00576 return true;
00577 QFile f(file);
00578 bool r = f.open(QIODevice::ReadOnly);
00579 if (!r) {
00580 return false;
00581 }
00582
00583 if (f.read(4) == "qres")
00584 return true;
00585
00586 return false;
00587 }
00588
00589 virtual bool canOpenData(const QByteArray& data)
00590 {
00591
00592
00593 return false;
00594 }
00595
00596 virtual bool openFile(const QString& file)
00597 {
00598 KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00599 klfDbg("file="<<file);
00600
00601 if (!canOpenFile(file)) {
00602 klfDbg("file is not openable by us: "<<file);
00603 return false;
00604 }
00605
00606 mainWin()->settingsDialog()->show();
00607 mainWin()->settingsDialog()->showControl(KLFSettings::ManageAddOns);
00608 mainWin()->settingsDialog()->importAddOn(file, true);
00609
00610 return true;
00611 }
00612
00613 virtual bool openData(const QByteArray& , const QString& )
00614 {
00615 return false;
00616 }
00617 };
00618
00619
00620
00621
00622 #endif