[KLF Application][KLF Tools][KLF Backend][KLF Home]
KLatexFormula Project

src/klfmainwin.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   file klfmainwin.cpp
00003  *   This file is part of the KLatexFormula Project.
00004  *   Copyright (C) 2007 by Philippe Faist
00005  *   philippe.faist at bluewin.ch
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU General Public License as published by  *
00009  *   the Free Software Foundation; either version 2 of the License, or     *
00010  *   (at your option) any later version.                                   *
00011  *                                                                         *
00012  *   This program is distributed in the hope that it will be useful,       *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015  *   GNU General Public License for more details.                          *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU General Public License     *
00018  *   along with this program; if not, write to the                         *
00019  *   Free Software Foundation, Inc.,                                       *
00020  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00021  ***************************************************************************/
00022 /* $Id: klfmainwin.cpp 570 2010-11-27 00:59:33Z philippe $ */
00023 
00024 #include <stdio.h>
00025 
00026 #include <QtCore>
00027 #include <QtGui>
00028 
00029 #include <klfbackend.h>
00030 
00031 #include <ui_klfprogerr.h>
00032 #include <ui_klfmainwin.h>
00033 
00034 #include <klflibview.h>
00035 #include <klfguiutil.h>
00036 
00037 #include "klflatexedit.h"
00038 #include "klflibbrowser.h"
00039 #include "klflatexsymbols.h"
00040 #include "klfsettings.h"
00041 #include "klfmain.h"
00042 #include "klfstylemanager.h"
00043 #include "klfmime.h"
00044 
00045 #include "klfmainwin.h"
00046 #include "klfmainwin_p.h"
00047 
00048 
00049 #define DEBUG_GEOM_ARGS(g) (g).topLeft().x(), (g).topLeft().y(), (g).size().width(), (g).size().height()
00050 
00051 static QRect klf_get_window_geometry(QWidget *w)
00052 {
00053 #if defined(Q_WS_X11)
00054   QRect g = w->frameGeometry();
00055 #else
00056   QRect g = w->geometry();
00057 #endif
00058   return g;
00059 }
00060 
00061 static void klf_set_window_geometry(QWidget *w, QRect g)
00062 {
00063   if ( ! g.isValid() )
00064     return;
00065 
00066   w->setGeometry(g);
00067 }
00068 
00069 
00070 
00071 
00072 
00073 
00074 
00075 // ------------------------------------------------------------------------
00076 
00077 KLFProgErr::KLFProgErr(QWidget *parent, QString errtext) : QDialog(parent)
00078 {
00079   u = new Ui::KLFProgErr;
00080   u->setupUi(this);
00081   setObjectName("KLFProgErr");
00082 
00083   u->txtError->setText(errtext);
00084 }
00085 
00086 KLFProgErr::~KLFProgErr()
00087 {
00088   delete u;
00089 }
00090 
00091 void KLFProgErr::showError(QWidget *parent, QString errtext)
00092 {
00093   KLFProgErr dlg(parent, errtext);
00094   dlg.exec();
00095 }
00096 
00097 
00098 
00099 // ----------------------------------------------------------------------------
00100 
00101 KLFPreviewBuilderThread::KLFPreviewBuilderThread(QObject *parent, KLFBackend::klfInput input,
00102                                                  KLFBackend::klfSettings settings, int labelwidth,
00103                                                  int labelheight)
00104   : QThread(parent), _input(input), _settings(settings), _lwidth(labelwidth), _lheight(labelheight),
00105     _hasnewinfo(false), _abort(false)
00106 {
00107 }
00108 KLFPreviewBuilderThread::~KLFPreviewBuilderThread()
00109 {
00110   _mutex.lock();
00111   _abort = true;
00112   _condnewinfoavail.wakeOne();
00113   _mutex.unlock();
00114   wait();
00115 }
00116 
00117 void KLFPreviewBuilderThread::run()
00118 {
00119   KLFBackend::klfInput input;
00120   KLFBackend::klfSettings settings;
00121   KLFBackend::klfOutput output;
00122   QImage img;
00123   int lwid, lhgt;
00124 
00125   for (;;) {
00126     _mutex.lock();
00127     bool abrt = _abort;
00128     _mutex.unlock();
00129     if (abrt)
00130       return;
00131   
00132     // fetch info
00133     _mutex.lock();
00134     input = _input;
00135     settings = _settings;
00136     settings.epstopdfexec = "";
00137     lwid = _lwidth;
00138     lhgt = _lheight;
00139     _hasnewinfo = false;
00140     _mutex.unlock();
00141     // render equation
00142     //  no performance improvement noticed with lower DPI:
00143     //    // force 240 DPI (we're only a preview...)
00144     //    input.dpi = 240;
00145 
00146     if ( input.latex.trimmed().isEmpty() ) {
00147       emit previewAvailable(QImage(), 0);
00148     } else {
00149       // and GO!
00150       output = KLFBackend::getLatexFormula(input, settings);
00151       img = output.result;
00152       if (output.status == 0) {
00153         if (img.width() > lwid || img.height() > lhgt)
00154           img = img.scaled(QSize(lwid, lhgt), Qt::KeepAspectRatio, Qt::SmoothTransformation);
00155       } else {
00156         img = QImage();
00157       }
00158     }
00159 
00160     _mutex.lock();
00161     bool abort = _abort;
00162     bool hasnewinfo = _hasnewinfo;
00163     _mutex.unlock();
00164 
00165     if (abort)
00166       return;
00167     if (hasnewinfo)
00168       continue;
00169 
00170     emit previewAvailable(img, output.status != 0);
00171 
00172     _mutex.lock();
00173     _condnewinfoavail.wait(&_mutex);
00174     _mutex.unlock();
00175   }
00176 }
00177 bool KLFPreviewBuilderThread::inputChanged(const KLFBackend::klfInput& input)
00178 {
00179   QMutexLocker mutexlocker(&_mutex);
00180   if (_input == input) {
00181     return false;
00182   }
00183   _input = input;
00184   _hasnewinfo = true;
00185   _condnewinfoavail.wakeOne();
00186   return true;
00187 }
00188 void KLFPreviewBuilderThread::settingsChanged(const KLFBackend::klfSettings& settings,
00189                                               int lwidth, int lheight)
00190 {
00191   _mutex.lock();
00192   _settings = settings;
00193   if (lwidth > 0) _lwidth = lwidth;
00194   if (lheight > 0) _lheight = lheight;
00195   _hasnewinfo = true;
00196   _condnewinfoavail.wakeOne();
00197   _mutex.unlock();
00198 }
00199 
00200 
00201 // ----------------------------------------------------------------------------
00202 
00203 
00204 KLFMainWin::KLFMainWin()
00205   : QWidget(0, Qt::Window)
00206 {
00207   u = new Ui::KLFMainWin;
00208   u->setupUi(this);
00209   setObjectName("KLFMainWin");
00210   setAttribute(Qt::WA_StyledBackground);
00211 
00212 #ifdef Q_WS_MAC
00213   // watch for QFileOpenEvent s on mac
00214   QApplication::instance()->installEventFilter(this);
00215 #endif
00216 
00217   mPopup = NULL;
00218 
00219   loadSettings();
00220 
00221   _firstshow = true;
00222 
00223   _output.status = 0;
00224   _output.errorstr = QString();
00225 
00226 
00227   // load styless
00228   loadStyles();
00229 
00230   mLatexSymbols = new KLFLatexSymbols(this, _settings);
00231 
00232   u->txtLatex->setFont(klfconfig.UI.latexEditFont);
00233   u->txtPreamble->setFont(klfconfig.UI.preambleEditFont);
00234 
00235   u->frmOutput->setEnabled(false);
00236 
00237   QMenu *DPIPresets = new QMenu(this);
00238   // 1200 DPI
00239   connect(u->aDPI1200, SIGNAL(triggered()), this, SLOT(slotPresetDPISender()));
00240   u->aDPI1200->setData(1200);
00241   DPIPresets->addAction(u->aDPI1200);
00242   // 600 DPI
00243   connect(u->aDPI600, SIGNAL(triggered()), this, SLOT(slotPresetDPISender()));
00244   u->aDPI600->setData(600);
00245   DPIPresets->addAction(u->aDPI600);
00246   // 300 DPI
00247   connect(u->aDPI300, SIGNAL(triggered()), this, SLOT(slotPresetDPISender()));
00248   u->aDPI300->setData(300);
00249   DPIPresets->addAction(u->aDPI300);
00250   // 150 DPI
00251   connect(u->aDPI150, SIGNAL(triggered()), this, SLOT(slotPresetDPISender()));
00252   u->aDPI150->setData(150);
00253   DPIPresets->addAction(u->aDPI150);
00254   // set menu to the button
00255   u->btnDPIPresets->setMenu(DPIPresets);
00256 
00257 
00258   connect(u->txtLatex->syntaxHighlighter(), SIGNAL(newSymbolTyped(const QString&)),
00259           this, SLOT(slotNewSymbolTyped(const QString&)));
00260 
00261   u->lblOutput->setLabelFixedSize(klfconfig.UI.labelOutputFixedSize);
00262   u->lblOutput->setEnableToolTipPreview(klfconfig.UI.enableToolTipPreview);
00263   u->lblOutput->setGlowEffect(klfconfig.UI.glowEffect);
00264   u->lblOutput->setGlowEffectColor(klfconfig.UI.glowEffectColor);
00265   u->lblOutput->setGlowEffectRadius(klfconfig.UI.glowEffectRadius);
00266 
00267   connect(u->lblOutput, SIGNAL(labelDrag()), this, SLOT(slotDrag()));
00268 
00269   connect(u->btnShowBigPreview, SIGNAL(clicked()),
00270           this, SLOT(slotShowBigPreview()));
00271 
00272   int h;
00273   h = u->btnDrag->sizeHint().height();  u->btnDrag->setFixedHeight(h - 5);
00274   h = u->btnCopy->sizeHint().height();  u->btnCopy->setFixedHeight(h - 5);
00275   h = u->btnSave->sizeHint().height();  u->btnSave->setFixedHeight(h - 5);
00276 
00277   QGridLayout *lyt = new QGridLayout(u->lblOutput);
00278   lyt->setSpacing(0);
00279   lyt->setMargin(0);
00280   mExportMsgLabel = new QLabel(u->lblOutput);
00281   //mExportMsgLabel = new QLabel(frmOutput);
00282   mExportMsgLabel->setObjectName("mExportMsgLabel");
00283   QFont smallfont = mExportMsgLabel->font();
00284   smallfont.setPointSize(QFontInfo(smallfont).pointSize() - 1);
00285   mExportMsgLabel->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
00286   mExportMsgLabel->setFont(smallfont);
00287   mExportMsgLabel->setMargin(1);
00288   mExportMsgLabel->setAlignment(Qt::AlignRight|Qt::AlignBottom);
00289   QPalette pal = mExportMsgLabel->palette();
00290   pal.setColor(QPalette::Window, QColor(180,180,180,200));
00291   pal.setColor(QPalette::WindowText, QColor(0,0,0,255));
00292   mExportMsgLabel->setPalette(pal);
00293   mExportMsgLabel->setAutoFillBackground(true);
00294   mExportMsgLabel->setProperty("defaultPalette", QVariant::fromValue<QPalette>(pal));
00295   //u->lyt_frmOutput->addWidget(mExportMsgLabel, 5, 0, 1, 2, Qt::AlignRight|Qt::AlignBottom);
00296   lyt->addItem(new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding), 0, 1, 2, 1);
00297   //  lyt->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Fixed), 1, 0, 1, 1);
00298   lyt->addWidget(mExportMsgLabel, 1, 0, 1, 2);
00299 
00300   pExportMsgLabelTimerId = -1;
00301 
00302   mExportMsgLabel->hide();
00303 
00304   refreshWindowSizes();
00305 
00306   u->frmDetails->hide();
00307 
00308   u->txtLatex->installEventFilter(this);
00309   u->txtLatex->setMainWinDataOpener(this);
00310 
00311   setFixedSize(_shrinkedsize);
00312 
00313   u->btnEvaluate->installEventFilter(this);
00314 
00315   // for appropriate tooltips
00316   u->btnDrag->installEventFilter(this);
00317   u->btnCopy->installEventFilter(this);
00318 
00319   // Shortcut for quit
00320   new QShortcut(QKeySequence(tr("Ctrl+Q")), this, SLOT(quit()), SLOT(quit()),
00321                 Qt::ApplicationShortcut);
00322 
00323   // Shortcut for activating editor
00324   //  QShortcut *editorActivatorShortcut = 
00325   new QShortcut(QKeySequence(Qt::Key_F4), this, SLOT(slotActivateEditor()),
00326                 SLOT(slotActivateEditor()), Qt::ApplicationShortcut);
00327   //  QShortcut *editorActivatorShortcut = 
00328   new QShortcut(QKeySequence(Qt::Key_F4 | Qt::ShiftModifier), this, SLOT(slotActivateEditorSelectAll()),
00329                 SLOT(slotActivateEditorSelectAll()), Qt::ApplicationShortcut);
00330   // shortcut for big preview
00331   new QShortcut(QKeySequence(Qt::Key_F2), this, SLOT(slotShowBigPreview()),
00332                 SLOT(slotShowBigPreview()), Qt::WindowShortcut);
00333 
00334   // Create our style manager
00335   mStyleManager = new KLFStyleManager(&_styles, this);
00336   connect(mStyleManager, SIGNAL(refreshStyles()), this, SLOT(refreshStylePopupMenus()));
00337   connect(this, SIGNAL(stylesChanged()), mStyleManager, SLOT(slotRefresh()));
00338 
00339   connect(this, SIGNAL(stylesChanged()), this, SLOT(saveStyles()));
00340   connect(mStyleManager, SIGNAL(refreshStyles()), this, SLOT(saveStyles()));
00341 
00342   loadDefaultStyle();
00343 
00344   // For systematical syntax highlighting
00345   // make sure syntax highlighting is up-to-date at all times
00346   QTimer *synthighlighttimer = new QTimer(this);
00347   connect(synthighlighttimer, SIGNAL(timeout()), u->txtLatex->syntaxHighlighter(), SLOT(refreshAll()));
00348   connect(synthighlighttimer, SIGNAL(timeout()), u->txtPreamble->syntaxHighlighter(), SLOT(refreshAll()));
00349   synthighlighttimer->start(250);
00350 
00351   // initialize the margin unit selector
00352   u->cbxMarginsUnit->setCurrentUnitAbbrev("pt");
00353 
00354   // set custom math modes
00355   u->cbxMathMode->addItems(klfconfig.UI.customMathModes);
00356 
00357   // load library
00358   mLibBrowser = new KLFLibBrowser(this);
00359 
00360   refreshShowCorrectClearButton();
00361 
00362   // -- MAJOR SIGNAL/SLOT CONNECTIONS --
00363 
00364   //  connect(u->btnClear, SIGNAL(toggled(bool)), this, SLOT(slotClear()));
00365   connect(u->aClearLatex, SIGNAL(triggered()), this, SLOT(slotClearLatex()));
00366   connect(u->aClearAll, SIGNAL(triggered()), this, SLOT(slotClearAll()));
00367   connect(u->btnEvaluate, SIGNAL(clicked()), this, SLOT(slotEvaluate()));
00368   connect(u->btnSymbols, SIGNAL(toggled(bool)), this, SLOT(slotSymbols(bool)));
00369   connect(u->btnLibrary, SIGNAL(toggled(bool)), this, SLOT(slotLibrary(bool)));
00370   connect(u->btnExpand, SIGNAL(clicked()), this, SLOT(slotExpandOrShrink()));
00371   connect(u->btnCopy, SIGNAL(clicked()), this, SLOT(slotCopy()));
00372   connect(u->btnDrag, SIGNAL(released()), this, SLOT(slotDrag()));
00373   connect(u->btnSave, SIGNAL(clicked()), this, SLOT(slotSave()));
00374   connect(u->btnSettings, SIGNAL(clicked()), this, SLOT(slotSettings()));
00375   connect(u->btnSaveStyle, SIGNAL(clicked()), this, SLOT(slotSaveStyle()));
00376 
00377   connect(u->btnQuit, SIGNAL(clicked()), this, SLOT(quit()));
00378 
00379   connect(mLibBrowser, SIGNAL(requestRestore(const KLFLibEntry&, uint)),
00380           this, SLOT(restoreFromLibrary(const KLFLibEntry&, uint)));
00381   connect(mLibBrowser, SIGNAL(requestRestoreStyle(const KLFStyle&)),
00382           this, SLOT(slotLoadStyle(const KLFStyle&)));
00383   connect(mLatexSymbols, SIGNAL(insertSymbol(const KLFLatexSymbol&)),
00384           this, SLOT(insertSymbol(const KLFLatexSymbol&)));
00385 
00386 
00387   // our help/about dialog
00388   connect(u->btnHelp, SIGNAL(clicked()), this, SLOT(showAbout()));
00389 
00390   // -- SMALL REAL-TIME PREVIEW GENERATOR THREAD --
00391 
00392   mPreviewBuilderThread = new KLFPreviewBuilderThread(this, collectInput(false), _settings,
00393                                                       klfconfig.UI.labelOutputFixedSize.width(),
00394                                                       klfconfig.UI.labelOutputFixedSize.height());
00395 
00396   connect(u->txtLatex, SIGNAL(textChanged()), this,
00397           SLOT(updatePreviewBuilderThreadInput()), Qt::QueuedConnection);
00398   connect(u->txtLatex, SIGNAL(insertContextMenuActions(const QPoint&, QList<QAction*> *)),
00399           this, SLOT(slotEditorContextMenuInsertActions(const QPoint&, QList<QAction*> *)));
00400   connect(u->cbxMathMode, SIGNAL(editTextChanged(const QString&)),
00401           this, SLOT(updatePreviewBuilderThreadInput()),
00402           Qt::QueuedConnection);
00403   connect(u->chkMathMode, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewBuilderThreadInput()),
00404           Qt::QueuedConnection);
00405   connect(u->colFg, SIGNAL(colorChanged(const QColor&)), this, SLOT(updatePreviewBuilderThreadInput()),
00406           Qt::QueuedConnection);
00407   connect(u->chkBgTransparent, SIGNAL(stateChanged(int)), this, SLOT(updatePreviewBuilderThreadInput()),
00408           Qt::QueuedConnection);
00409   connect(u->colBg, SIGNAL(colorChanged(const QColor&)), this, SLOT(updatePreviewBuilderThreadInput()),
00410           Qt::QueuedConnection);
00411 
00412   connect(mPreviewBuilderThread, SIGNAL(previewAvailable(const QImage&, bool)),
00413           this, SLOT(showRealTimePreview(const QImage&, bool)), Qt::QueuedConnection);
00414 
00415   if (klfconfig.UI.enableRealTimePreview) {
00416     mPreviewBuilderThread->start();
00417   }
00418 
00419   // CREATE SETTINGS DIALOG
00420 
00421   mSettingsDialog = new KLFSettings(this);
00422 
00423 
00424   // INSTALL SOME EVENT FILTERS... FOR show/hide EVENTS
00425 
00426   mLibBrowser->installEventFilter(this);
00427   mLatexSymbols->installEventFilter(this);
00428   mStyleManager->installEventFilter(this);
00429   mSettingsDialog->installEventFilter(this);
00430 
00431 
00432   // INTERNAL FLAGS
00433 
00434   _evaloutput_uptodate = true;
00435 
00436   retranslateUi(false);
00437 
00438   connect(this, SIGNAL(applicationLocaleChanged(const QString&)), this, SLOT(retranslateUi()));
00439   connect(this, SIGNAL(applicationLocaleChanged(const QString&)), mLibBrowser, SLOT(retranslateUi()));
00440   connect(this, SIGNAL(applicationLocaleChanged(const QString&)), mSettingsDialog, SLOT(retranslateUi()));
00441   connect(this, SIGNAL(applicationLocaleChanged(const QString&)), mStyleManager, SLOT(retranslateUi()));
00442 
00443   // About Dialog & What's New dialog
00444   mAboutDialog = new KLFAboutDialog(this);
00445   mWhatsNewDialog = new KLFWhatsNewDialog(this);
00446 
00447   connect(mAboutDialog, SIGNAL(linkActivated(const QUrl&)), this, SLOT(helpLinkAction(const QUrl&)));
00448   connect(mWhatsNewDialog, SIGNAL(linkActivated(const QUrl&)), this, SLOT(helpLinkAction(const QUrl&)));
00449 
00450   mHelpLinkActions << HelpLinkAction("/whats_new", this, "showWhatsNew", false);
00451   mHelpLinkActions << HelpLinkAction("/about", this, "showAbout", false);
00452   mHelpLinkActions << HelpLinkAction("/popup_close", this, "slotPopupClose", false);
00453   mHelpLinkActions << HelpLinkAction("/popup", this, "slotPopupAction", true);
00454   mHelpLinkActions << HelpLinkAction("/settings", this, "showSettingsHelpLinkAction", true);
00455 
00456   if ( klfconfig.Core.thisVersionMajMinFirstRun && ! klfconfig.checkExePaths() ) {
00457     addWhatsNewText("<p><b><span style=\"color: #a00000\">"+
00458                     tr("Your executable paths (latex, dvips, gs) seem not to be detected properly. "
00459                        "Please adjust the settings in the <a href=\"klfaction:/settings?control="
00460                        "ExecutablePaths\">settings dialog</a>.",
00461                        "[[additional text in what's-new-dialog in case of bad detected settings. this "
00462                        "is HTML formatted text.]]")
00463                     +"</span></b></p>");
00464   }
00465 
00466   klfDbg("Font is "<<font()<<", family is "<<fontInfo().family()) ;
00467   if (QFontInfo(klfconfig.UI.applicationFont).family().contains("CMU")) {
00468     addWhatsNewText("<p>"+tr("LaTeX' Computer Modern Sans Serif font is used as the <b>default application font</b>."
00469                              " Don't like it? <a href=\"%1\">Choose your preferred application font</a>.")
00470                     .arg("klfaction:/settings?control=AppFonts") + "</p>");
00471   }
00472 
00473   // and load the library
00474 
00475   _loadedlibrary = true;
00476   loadLibrary();
00477 
00478   registerDataOpener(new KLFBasicDataOpener(this));
00479   registerDataOpener(new KLFAddOnDataOpener(this));
00480 }
00481 
00482 void KLFMainWin::retranslateUi(bool alsoBaseUi)
00483 {
00484   if (alsoBaseUi)
00485     u->retranslateUi(this);
00486 
00487   // version information as tooltip on the welcome widget
00488   u->lblPromptMain->setToolTip(tr("KLatexFormula %1").arg(QString::fromUtf8(KLF_VERSION_STRING)));
00489 
00490   refreshStylePopupMenus();
00491 }
00492 
00493 
00494 KLFMainWin::~KLFMainWin()
00495 {
00496   klfDbg( "()" ) ;
00497 
00498   saveLibraryState();
00499   saveSettings();
00500   saveStyles();
00501 
00502   if (mStyleMenu)
00503     delete mStyleMenu;
00504   if (mLatexSymbols)
00505     delete mLatexSymbols;
00506   if (mLibBrowser)
00507     delete mLibBrowser; // we aren't its parent
00508   if (mSettingsDialog)
00509     delete mSettingsDialog;
00510 
00511   if (mPreviewBuilderThread)
00512     delete mPreviewBuilderThread;
00513 
00514   delete u;
00515 }
00516 
00517 void KLFMainWin::startupFinished()
00518 {
00519   //  if ( ! _loadedlibrary ) {
00520   //    _loadedlibrary = true;
00521   //
00522   //    // load the library browser's saved state
00523   //    QMetaObject::invokeMethod(this, "loadLibrary", Qt::QueuedConnection);
00524   //  }
00525 
00526 
00527   // Export profiles selection list
00528 
00529   pExportProfileQuickMenuActionList.clear();
00530   int k;
00531   QList<KLFMimeExportProfile> eplist = KLFMimeExportProfile::exportProfileList();
00532   QMenu *menu = new QMenu(u->btnSetExportProfile);
00533   QActionGroup *actionGroup = new QActionGroup(menu);
00534   actionGroup->setExclusive(true);
00535   QSignalMapper *smapper = new QSignalMapper(menu);
00536   for (k = 0; k < eplist.size(); ++k) {
00537     QAction *action = new QAction(actionGroup);
00538     action->setText(eplist[k].description());
00539     action->setData(eplist[k].profileName());
00540     action->setCheckable(true);
00541     action->setChecked( (klfconfig.UI.dragExportProfile==klfconfig.UI.copyExportProfile) &&
00542                         (klfconfig.UI.dragExportProfile==eplist[k].profileName()) );
00543     menu->addAction(action);
00544     smapper->setMapping(action, eplist[k].profileName());
00545     connect(action, SIGNAL(triggered()), smapper, SLOT(map()));
00546     pExportProfileQuickMenuActionList.append(action);
00547   }
00548   connect(smapper, SIGNAL(mapped(const QString&)), this, SLOT(slotSetExportProfile(const QString&)));
00549 
00550   u->btnSetExportProfile->setMenu(menu);
00551 }
00552 
00553 
00554 
00555 void KLFMainWin::refreshWindowSizes()
00556 {
00557   bool curstate_shown = u->frmDetails->isVisible();
00558   u->frmDetails->show();
00559   _shrinkedsize = u->frmMain->sizeHint() + QSize(3, 3);
00560   _expandedsize.setWidth(u->frmMain->sizeHint().width() + u->frmDetails->sizeHint().width() + 3);
00561   _expandedsize.setHeight(u->frmMain->sizeHint().height() + 3);
00562   if (curstate_shown) {
00563     setFixedSize(_expandedsize);
00564     u->frmDetails->show();
00565   } else {
00566     setFixedSize(_shrinkedsize);
00567     u->frmDetails->hide();
00568   }
00569   updateGeometry();
00570 }
00571 
00572 void KLFMainWin::refreshShowCorrectClearButton()
00573 {
00574   bool lo = klfconfig.UI.clearLatexOnly;
00575   u->btnClearAll->setVisible(!lo);
00576   u->btnClearLatex->setVisible(lo);
00577 }
00578 
00579 
00580 bool KLFMainWin::loadDefaultStyle()
00581 {
00582   // load style "default" or "Default" (or translation) if one of them exists
00583   bool r;
00584   r = loadNamedStyle(tr("Default", "[[style name]]"));
00585   r = r || loadNamedStyle("Default");
00586   r = r || loadNamedStyle("default");
00587   return r;
00588 }
00589 
00590 bool KLFMainWin::loadNamedStyle(const QString& sty)
00591 {
00592   // find style with name sty (if existant) and set it
00593   for (int kl = 0; kl < _styles.size(); ++kl) {
00594     if (_styles[kl].name == sty) {
00595       slotLoadStyle(kl);
00596       return true;
00597     }
00598   }
00599   return false;
00600 }
00601 
00602 void KLFMainWin::loadSettings()
00603 {
00604   _settings.tempdir = klfconfig.BackendSettings.tempDir;
00605   _settings.latexexec = klfconfig.BackendSettings.execLatex;
00606   _settings.dvipsexec = klfconfig.BackendSettings.execDvips;
00607   _settings.gsexec = klfconfig.BackendSettings.execGs;
00608   _settings.epstopdfexec = klfconfig.BackendSettings.execEpstopdf;
00609   _settings.execenv = klfconfig.BackendSettings.execenv;
00610 
00611   _settings.lborderoffset = klfconfig.BackendSettings.lborderoffset;
00612   _settings.tborderoffset = klfconfig.BackendSettings.tborderoffset;
00613   _settings.rborderoffset = klfconfig.BackendSettings.rborderoffset;
00614   _settings.bborderoffset = klfconfig.BackendSettings.bborderoffset;
00615 
00616   _settings.outlineFonts = klfconfig.BackendSettings.outlineFonts;
00617 
00618   _settings_altered = false;
00619 }
00620 
00621 void KLFMainWin::saveSettings()
00622 {
00623   if ( ! _settings_altered ) {    // don't save altered settings
00624     klfconfig.BackendSettings.tempDir = _settings.tempdir;
00625     klfconfig.BackendSettings.execLatex = _settings.latexexec;
00626     klfconfig.BackendSettings.execDvips = _settings.dvipsexec;
00627     klfconfig.BackendSettings.execGs = _settings.gsexec;
00628     klfconfig.BackendSettings.execEpstopdf = _settings.epstopdfexec;
00629     klfconfig.BackendSettings.execenv = _settings.execenv;
00630     klfconfig.BackendSettings.lborderoffset = _settings.lborderoffset;
00631     klfconfig.BackendSettings.tborderoffset = _settings.tborderoffset;
00632     klfconfig.BackendSettings.rborderoffset = _settings.rborderoffset;
00633     klfconfig.BackendSettings.bborderoffset = _settings.bborderoffset;
00634     klfconfig.BackendSettings.outlineFonts = _settings.outlineFonts;
00635   }
00636 
00637   klfconfig.UI.userColorList = KLFColorChooser::colorList();
00638   klfconfig.UI.colorChooseWidgetRecent = KLFColorChooseWidget::recentColors();
00639   klfconfig.UI.colorChooseWidgetCustom = KLFColorChooseWidget::customColors();
00640 
00641   klfconfig.writeToConfig();
00642 
00643   mPreviewBuilderThread->settingsChanged(_settings, klfconfig.UI.labelOutputFixedSize.width(),
00644                                          klfconfig.UI.labelOutputFixedSize.height());
00645 
00646   u->lblOutput->setLabelFixedSize(klfconfig.UI.labelOutputFixedSize);
00647   u->lblOutput->setEnableToolTipPreview(klfconfig.UI.enableToolTipPreview);
00648 
00649   u->lblOutput->setGlowEffect(klfconfig.UI.glowEffect);
00650   u->lblOutput->setGlowEffectColor(klfconfig.UI.glowEffectColor);
00651   u->lblOutput->setGlowEffectRadius(klfconfig.UI.glowEffectRadius);
00652 
00653   int k;
00654   if (klfconfig.UI.dragExportProfile == klfconfig.UI.copyExportProfile) {
00655     klfDbg("checking quick menu action item export profile="<<klfconfig.UI.copyExportProfile) ;
00656     // check this export profile in the quick export profile menu
00657     for (k = 0; k < pExportProfileQuickMenuActionList.size(); ++k) {
00658       if (pExportProfileQuickMenuActionList[k]->data().toString() == klfconfig.UI.copyExportProfile) {
00659         klfDbg("checking item #"<<k<<": "<<pExportProfileQuickMenuActionList[k]->data()) ;
00660         // found the one
00661         pExportProfileQuickMenuActionList[k]->setChecked(true);
00662         break; // by auto-exclusivity the other ones will be un-checked.
00663       }
00664     }
00665   } else {
00666     // uncheck all items (since there is not a unique one set, drag and copy differ)
00667     for (k = 0; k < pExportProfileQuickMenuActionList.size(); ++k)
00668       pExportProfileQuickMenuActionList[k]->setChecked(false);
00669   }
00670 
00671   u->btnSetExportProfile->setEnabled(klfconfig.UI.menuExportProfileAffectsDrag ||
00672                                      klfconfig.UI.menuExportProfileAffectsCopy);
00673 
00674   if (klfconfig.UI.enableRealTimePreview) {
00675     if ( ! mPreviewBuilderThread->isRunning() ) {
00676       delete mPreviewBuilderThread;
00677       mPreviewBuilderThread =
00678         new KLFPreviewBuilderThread(this, collectInput(false), _settings,
00679                                     klfconfig.UI.labelOutputFixedSize.width(),
00680                                     klfconfig.UI.labelOutputFixedSize.height());
00681       mPreviewBuilderThread->start();
00682     }
00683   } else {
00684     if ( mPreviewBuilderThread->isRunning() ) {
00685       delete mPreviewBuilderThread;
00686       // do NOT leave a NULL mPreviewBuilderThread !
00687       mPreviewBuilderThread =
00688         new KLFPreviewBuilderThread(this, collectInput(false), _settings,
00689                                     klfconfig.UI.labelOutputFixedSize.width(),
00690                                     klfconfig.UI.labelOutputFixedSize.height());
00691     }
00692   }
00693 }
00694 
00695 void KLFMainWin::showExportMsgLabel(const QString& msg, int timeout)
00696 {
00697   mExportMsgLabel->show();
00698   mExportMsgLabel->setPalette(mExportMsgLabel->property("defaultPalette").value<QPalette>());
00699 
00700   mExportMsgLabel->setProperty("timeTotal", timeout);
00701   mExportMsgLabel->setProperty("timeRemaining", timeout);
00702   mExportMsgLabel->setProperty("timeInterval", 200);
00703 
00704   mExportMsgLabel->setText(msg);
00705 
00706   if (pExportMsgLabelTimerId == -1) {
00707     pExportMsgLabelTimerId = startTimer(mExportMsgLabel->property("timeInterval").toInt());
00708   }
00709 }
00710 
00711 void KLFMainWin::refreshStylePopupMenus()
00712 {
00713   if (mStyleMenu == NULL)
00714     mStyleMenu = new QMenu(this);
00715   mStyleMenu->clear();
00716 
00717   QAction *a;
00718   for (int i = 0; i < _styles.size(); ++i) {
00719     a = mStyleMenu->addAction(_styles[i].name);
00720     a->setData(i);
00721     connect(a, SIGNAL(triggered()), this, SLOT(slotLoadStyleAct()));
00722   }
00723 
00724   mStyleMenu->addSeparator();
00725   mStyleMenu->addAction(QIcon(":/pics/managestyles.png"), tr("Manage Styles"),
00726                          this, SLOT(slotStyleManager()), 0 /* accel */);
00727 
00728 }
00729 
00730 
00731 
00732 static QString kdelocate(const char *fname)
00733 {
00734   QString candidate;
00735 
00736   QStringList env = QProcess::systemEnvironment();
00737   QStringList kdehome = env.filter(QRegExp("^KDEHOME="));
00738   if (kdehome.size() == 0) {
00739     candidate = QDir::homePath() + QString("/.kde/share/apps/klatexformula/") + QString::fromLocal8Bit(fname);
00740   } else {
00741     QString kdehomeval = kdehome[0];
00742     kdehomeval.replace(QRegExp("^KDEHOME="), "");
00743     candidate = kdehomeval + "/share/apps/klatexformula/" + QString::fromLocal8Bit(fname);
00744   }
00745   if (QFile::exists(candidate)) {
00746     return candidate;
00747   }
00748   return QString::null;
00749 }
00750 
00751 bool KLFMainWin::try_load_style_list(const QString& styfname)
00752 {
00753   if ( ! QFile::exists(styfname) )
00754     return false;
00755 
00756   QFile fsty(styfname);
00757   if ( ! fsty.open(QIODevice::ReadOnly) )
00758     return false;
00759 
00760   QDataStream str(&fsty);
00761 
00762   QString readHeader;
00763   QString readCompatKLFVersion;
00764   bool r = klfDataStreamReadHeader(str, QStringList()<<QLatin1String("KLATEXFORMULA_STYLE_LIST"),
00765                                    &readHeader, &readCompatKLFVersion);
00766   if (!r) {
00767     if (readHeader.isEmpty() || readCompatKLFVersion.isEmpty()) {
00768       QMessageBox::critical(this, tr("Error"), tr("Error: Style file is incorrect or corrupt!\n"));
00769       return false;
00770     }
00771     // too recent version warning
00772     QMessageBox::warning(this, tr("Load Styles"),
00773                          tr("The style file found was created by a more recent version "
00774                             "of KLatexFormula.\n"
00775                             "The process of style loading may fail.")
00776                          );
00777   }
00778   // read the header, just need to read data now
00779   str >> _styles;
00780   return true;
00781 }
00782 
00783 void KLFMainWin::loadStyles()
00784 {
00785   _styles = KLFStyleList(); // empty list to start with
00786 
00787   QStringList styfnamecandidates;
00788   styfnamecandidates << klfconfig.homeConfigDir + QString("/styles-klf%1").arg(KLF_DATA_STREAM_APP_VERSION)
00789                      << klfconfig.homeConfigDir + QLatin1String("/styles")
00790                      << QLatin1String("kde-locate"); // locate in KDE only if necessary in for loop below
00791 
00792   int k;
00793   bool result = false;
00794   for (k = 0; k < styfnamecandidates.size(); ++k) {
00795     QString fn = styfnamecandidates[k];
00796     if (fn == QLatin1String("kde-locate"))
00797       fn = kdelocate("styles");
00798     // try to load this file
00799     if ( (result = try_load_style_list(fn)) == true )
00800       break;
00801   }
00802   //  Don't fail if result is false, this is the case on first run (!)
00803   //  if (!result) {
00804   //    QMessageBox::critical(this, tr("Error"), tr("Error: Unable to load your style list!"));
00805   //  }
00806 
00807   if (_styles.isEmpty()) {
00808     // if stylelist is empty, populate with default style
00809     KLFStyle s1(tr("Default"), qRgb(0, 0, 0), qRgba(255, 255, 255, 0), "\\[ ... \\]", "", 600);
00810     //    KLFStyle s2(tr("Inline"), qRgb(0, 0, 0), qRgba(255, 255, 255, 0), "\\[ ... \\]", "", 150);
00811     //    s2.overrideBBoxExpand = KLFStyle::BBoxExpand(0,0,0,0);
00812     _styles.append(s1);
00813     //    _styles.append(s2);
00814   }
00815 
00816   mStyleMenu = 0;
00817   refreshStylePopupMenus();
00818 
00819   u->btnLoadStyle->setMenu(mStyleMenu);
00820 }
00821 
00822 void KLFMainWin::saveStyles()
00823 {
00824   klfconfig.ensureHomeConfigDir();
00825   QString s = klfconfig.homeConfigDir + QString("/styles-klf%1").arg(KLF_DATA_STREAM_APP_VERSION);
00826   QFile f(s);
00827   if ( ! f.open(QIODevice::WriteOnly) ) {
00828     QMessageBox::critical(this, tr("Error"), tr("Error: Unable to write to styles file!\n%1").arg(s));
00829     return;
00830   }
00831   QDataStream stream(&f);
00832 
00833   klfDataStreamWriteHeader(stream, "KLATEXFORMULA_STYLE_LIST");
00834 
00835   stream << _styles;
00836 }
00837 
00838 void KLFMainWin::loadLibrary()
00839 {
00840   KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00841 
00842   // start by loading the saved library browser state.
00843   // Inside this function the value of klfconfig.LibraryBrowser.restoreURLs is taken
00844   // into account.
00845   loadLibrarySavedState();
00846 
00847   // Locate a good library/history file.
00848 
00849   //  KLFPleaseWaitPopup pwp(tr("Loading library, please wait..."), this);
00850   //  pwp.showPleaseWait();
00851 
00852   // the default library file
00853   QString localfname = klfconfig.Core.libraryFileName;
00854   if (QFileInfo(localfname).isRelative())
00855     localfname.prepend(klfconfig.homeConfigDir + "/");
00856 
00857   QString importfname;
00858   if ( ! QFile::exists(localfname) ) {
00859     // if unexistant, try to load:
00860     importfname = klfconfig.homeConfigDir + "/library"; // the 3.1 library file
00861     if ( ! QFile::exists(importfname) )
00862       importfname = kdelocate("library"); // or the KDE KLF 2.1 library file
00863     if ( ! QFile::exists(importfname) )
00864       importfname = kdelocate("history"); // or the KDE KLF 2.0 history file
00865     if ( ! QFile::exists(importfname) ) {
00866       // as last resort we load our default library bundled with KLatexFormula
00867       importfname = ":/data/defaultlibrary.klf";
00868     }
00869   }
00870 
00871   // importfname is non-empty only if the local .klf.db library file is inexistant.
00872 
00873   QUrl localliburl = QUrl::fromLocalFile(localfname);
00874   localliburl.setScheme(klfconfig.Core.libraryLibScheme);
00875   localliburl.addQueryItem("klfDefaultSubResource", "History");
00876 
00877   // If the history is already open from library browser saved state, retrieve it
00878   // This is possibly NULL
00879   mHistoryLibResource = mLibBrowser->getOpenResource(localliburl);
00880 
00881   if (!QFile::exists(localfname)) {
00882     // create local library resource
00883     KLFLibEngineFactory *localLibFactory = KLFLibEngineFactory::findFactoryFor(localliburl.scheme());
00884     if (localLibFactory == NULL) {
00885       qWarning()<<KLF_FUNC_NAME<<": Can't find library resource engine factory for scheme "<<localliburl.scheme()<<"!";
00886       qFatal("%s: Can't find library resource engine factory for scheme '%s'!",
00887              KLF_FUNC_NAME, qPrintable(localliburl.scheme()));
00888       return;
00889     }
00890     KLFLibEngineFactory::Parameters param;
00891     param["Filename"] = localliburl.path();
00892     param["klfDefaultSubResource"] = QLatin1String("History");
00893     param["klfDefaultSubResourceTitle"] = tr("History", "[[default sub-resource title for history]]");
00894     mHistoryLibResource = localLibFactory->createResource(localliburl.scheme(), param, this);
00895     if (mHistoryLibResource == NULL) {
00896       qWarning()<<KLF_FUNC_NAME<<": Can't create resource engine for library, of scheme "<<localliburl.scheme()<<"! "
00897                 <<"Create parameters are "<<param;
00898       qFatal("%s: Can't create resource engine for library!", KLF_FUNC_NAME);
00899       return;
00900     }
00901     mHistoryLibResource->setTitle(tr("Local Library"));
00902     mHistoryLibResource
00903       -> createSubResource(QLatin1String("Archive"),
00904                            tr("Archive", "[[default sub-resource title for archive sub-resource]]"));
00905     if (mHistoryLibResource->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResourceProps) {
00906       mHistoryLibResource->setSubResourceProperty(QLatin1String("History"),
00907                                                   KLFLibResourceEngine::SubResPropViewType,
00908                                                   QLatin1String("default+list"));
00909       mHistoryLibResource->setSubResourceProperty(QLatin1String("Archive"),
00910                                                   KLFLibResourceEngine::SubResPropViewType,
00911                                                   QLatin1String("default"));
00912     } else {
00913       mHistoryLibResource->setViewType(QLatin1String("default+list"));
00914     }
00915   }
00916 
00917   if (mHistoryLibResource == NULL) {
00918     mHistoryLibResource = KLFLibEngineFactory::openURL(localliburl, this);
00919   }
00920   if (mHistoryLibResource == NULL) {
00921     qWarning()<<"KLFMainWin::loadLibrary(): Can't open local history resource!\n\tURL="<<localliburl
00922               <<"\n\tNot good! Expect crash!";
00923     return;
00924   }
00925 
00926   klfDbg("opened history: resource-ptr="<<mHistoryLibResource<<"\n\tImportFile="<<importfname);
00927 
00928   if (!importfname.isEmpty()) {
00929     // needs an import
00930     klfDbg("Importing library from "<<importfname) ;
00931 
00932     // visual feedback for import
00933     KLFProgressDialog pdlg(QString(), this);
00934     connect(mHistoryLibResource, SIGNAL(operationStartReportingProgress(KLFProgressReporter *,
00935                                                                         const QString&)),
00936             &pdlg, SLOT(startReportingProgress(KLFProgressReporter *)));
00937     pdlg.setAutoClose(false);
00938     pdlg.setAutoReset(false);
00939 
00940     // locate the import file and scheme
00941     QUrl importliburl = QUrl::fromLocalFile(importfname);
00942     QString scheme = KLFLibBasicWidgetFactory::guessLocalFileScheme(importfname);
00943     if (scheme.isEmpty()) {
00944       // assume .klf if not able to guess
00945       scheme = "klf+legacy";
00946     }
00947     importliburl.setScheme(scheme);
00948     importliburl.addQueryItem("klfReadOnly", "true");
00949     // import library from an older version library file.
00950     KLFLibEngineFactory *factory = KLFLibEngineFactory::findFactoryFor(importliburl.scheme());
00951     if (factory == NULL) {
00952       qWarning()<<"KLFMainWin::loadLibrary(): Can't find factory for URL="<<importliburl<<"!";
00953     } else {
00954       KLFLibResourceEngine *importres = factory->openResource(importliburl, this);
00955       // import all sub-resources
00956       QStringList subResList = importres->subResourceList();
00957       klfDbg( "\tImporting sub-resources: "<<subResList ) ;
00958       int j;
00959       for (j = 0; j < subResList.size(); ++j) {
00960         QString subres = subResList[j];
00961         pdlg.setDescriptiveText(tr("Importing Library from previous version of KLatexFormula ... "
00962                                    "%3 (%1/%2)")
00963                                 .arg(j+1).arg(subResList.size()).arg(subResList[j]));
00964         QList<KLFLibResourceEngine::KLFLibEntryWithId> allentries
00965           = importres->allEntries(subres);
00966         klfDbg("Got "<<allentries.size()<<" entries from sub-resource "<<subres);
00967         int k;
00968         KLFLibEntryList insertentries;
00969         for (k = 0; k < allentries.size(); ++k) {
00970           insertentries << allentries[k].entry;
00971         }
00972         if ( ! mHistoryLibResource->hasSubResource(subres) ) {
00973           mHistoryLibResource->createSubResource(subres);
00974         }
00975         mHistoryLibResource->insertEntries(subres, insertentries);
00976       }
00977     }
00978   }
00979 
00980   // Open history sub-resource into library browser
00981   bool r;
00982   r = mLibBrowser->openResource(mHistoryLibResource,
00983                                 KLFLibBrowser::NoCloseRoleFlag|KLFLibBrowser::OpenNoRaise,
00984                                 QLatin1String("default+list"));
00985   if ( ! r ) {
00986     qWarning()<<"KLFMainWin::loadLibrary(): Can't open local history resource!\n\tURL="<<localliburl
00987               <<"\n\tExpect Crash!";
00988     return;
00989   }
00990 
00991   // open all other sub-resources present in our library
00992   QStringList subresources = mHistoryLibResource->subResourceList();
00993   int k;
00994   for (k = 0; k < subresources.size(); ++k) {
00995     //    if (subresources[k] == QLatin1String("History")) // already open
00996     //      continue;
00997     // if a URL is already open, it won't open it a second time.
00998     QUrl url = localliburl;
00999     url.removeAllQueryItems("klfDefaultSubResource");
01000     url.addQueryItem("klfDefaultSubResource", subresources[k]);
01001 
01002     uint flags = KLFLibBrowser::NoCloseRoleFlag|KLFLibBrowser::OpenNoRaise;
01003     QString sr = subresources[k].toLower();
01004     if (sr == "history" || sr == tr("History").toLower())
01005       flags |= KLFLibBrowser::HistoryRoleFlag;
01006     if (sr == "archive" || sr == tr("Archive").toLower())
01007       flags |= KLFLibBrowser::ArchiveRoleFlag;
01008 
01009     mLibBrowser->openResource(url, flags);
01010   }
01011 }
01012 
01013 void KLFMainWin::loadLibrarySavedState()
01014 {
01015   QString fname = klfconfig.homeConfigDir + "/libbrowserstate.xml";
01016   if ( ! QFile::exists(fname) ) {
01017     klfDbg("No saved library browser state found ("<<fname<<")");
01018     return;
01019   }
01020 
01021   QFile f(fname);
01022   if ( ! f.open(QIODevice::ReadOnly) ) {
01023     qWarning()<<"Can't open file "<<fname<<" for loading library browser state";
01024     return;
01025   }
01026   QDomDocument doc("klflibbrowserstate");
01027   doc.setContent(&f);
01028   f.close();
01029 
01030   QDomNode rootNode = doc.documentElement();
01031   if (rootNode.nodeName() != "klflibbrowserstate") {
01032     qWarning()<<"Invalid root node in file "<<fname<<" !";
01033     return;
01034   }
01035   QDomNode n;
01036   QVariantMap vstatemap;
01037   for (n = rootNode.firstChild(); ! n.isNull(); n = n.nextSibling()) {
01038     QDomElement e = n.toElement();
01039     if ( e.isNull() || n.nodeType() != QDomNode::ElementNode )
01040       continue;
01041     if ( e.nodeName() == "statemap" ) {
01042       vstatemap = klfLoadVariantMapFromXML(e);
01043       continue;
01044     }
01045 
01046     qWarning("%s: Ignoring unrecognized node `%s' in file %s.", KLF_FUNC_NAME,
01047              qPrintable(e.nodeName()), qPrintable(fname));
01048   }
01049 
01050   mLibBrowser->loadGuiState(vstatemap, klfconfig.LibraryBrowser.restoreURLs);
01051 }
01052 
01053 void KLFMainWin::saveLibraryState()
01054 {
01055   QString fname = klfconfig.homeConfigDir + "/libbrowserstate.xml";
01056 
01057   QVariantMap statemap = mLibBrowser->saveGuiState();
01058 
01059   QFile f(fname);
01060   if ( ! f.open(QIODevice::WriteOnly) ) {
01061     qWarning()<<"Can't open file "<<fname<<" for saving library browser state";
01062     return;
01063   }
01064 
01065   QDomDocument doc("klflibbrowserstate");
01066   QDomElement rootNode = doc.createElement("klflibbrowserstate");
01067   QDomElement statemapNode = doc.createElement("statemap");
01068 
01069   klfSaveVariantMapToXML(statemap, statemapNode);
01070 
01071   rootNode.appendChild(statemapNode);
01072   doc.appendChild(rootNode);
01073 
01074   f.write(doc.toByteArray(2));
01075 }
01076 
01077 // private
01078 void KLFMainWin::slotOpenHistoryLibraryResource()
01079 {
01080   KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
01081 
01082   bool r;
01083   r = mLibBrowser->openResource(mHistoryLibResource, KLFLibBrowser::NoCloseRoleFlag,
01084                                 QLatin1String("default+list"));
01085   if ( ! r )
01086     qWarning()<<KLF_FUNC_NAME<<": Can't open local history resource!";
01087 
01088 }
01089 
01090 
01091 
01092 void KLFMainWin::restoreFromLibrary(const KLFLibEntry& entry, uint restoreFlags)
01093 {
01094   if (restoreFlags & KLFLib::RestoreStyle) {
01095     KLFStyle style = entry.style();
01096     slotLoadStyle(style);
01097   }
01098   // restore latex after style, so that the parser-hint-popup doesn't appear for packages
01099   // that we're going to include anyway
01100   if (restoreFlags & KLFLib::RestoreLatex) {
01101     // to preserve text edit undo history... call this slot instead of brutally doing txt->setPlainText(..)
01102     slotSetLatex(entry.latexWithCategoryTagsComments());
01103   }
01104 
01105   u->lblOutput->display(entry.preview(), entry.preview(), false);
01106   u->frmOutput->setEnabled(false);
01107   activateWindow();
01108   raise();
01109   u->txtLatex->setFocus();
01110 }
01111 
01112 void KLFMainWin::slotLibraryButtonRefreshState(bool on)
01113 {
01114   u->btnLibrary->setChecked(on);
01115 }
01116 
01117 
01118 void KLFMainWin::insertSymbol(const KLFLatexSymbol& s)
01119 {
01120   // see if we need to insert the xtrapreamble
01121   QStringList cmds = s.preamble;
01122   int k;
01123   QString preambletext = u->txtPreamble->toPlainText();
01124   QString addtext;
01125   for (k = 0; k < cmds.size(); ++k) {
01126     slotEnsurePreambleCmd(cmds[k]);
01127   }
01128 
01129   // only after actually insert the symbol, so as not to interfere with popup package suggestions.
01130 
01131   QTextCursor c1(u->txtLatex->document());
01132   c1.beginEditBlock();
01133   c1.setPosition(u->txtLatex->textCursor().position());
01134   c1.insertText(s.symbol+"\n");
01135   c1.deletePreviousChar(); // small hack for forcing a separate undo command when two symbols are inserted
01136   c1.endEditBlock();
01137 
01138   activateWindow();
01139   raise();
01140   u->txtLatex->setFocus();
01141 }
01142 
01143 void KLFMainWin::insertDelimiter(const QString& delim, int charsBack)
01144 {
01145   u->txtLatex->insertDelimiter(delim, charsBack);
01146 }
01147 
01148 
01149 void KLFMainWin::getMissingCmdsFor(const QString& symbol, QStringList * missingCmds,
01150                                    QString *guiText, bool wantHtmlText)
01151 {
01152   if (missingCmds == NULL) {
01153     qWarning()<<KLF_FUNC_NAME<<": missingCmds is NULL!";
01154     return;
01155   }
01156   if (guiText == NULL) {
01157     qWarning()<<KLF_FUNC_NAME<<": guiText is NULL!";
01158     return;
01159   }
01160 
01161   missingCmds->clear();
01162   *guiText = QString();
01163 
01164   if (symbol.isEmpty())
01165     return;
01166 
01167   KLFLatexSymbol sym = KLFLatexSymbolsCache::theCache()->findSymbol(symbol);
01168   if (!sym.valid())
01169     return;
01170 
01171   QStringList cmds = sym.preamble;
01172   klfDbg("Got symbol for "<<symbol<<"; cmds is "<<cmds);
01173   if (cmds.isEmpty()) {
01174     return; // no need to include anything
01175   }
01176 
01177   QString curpreambletext = u->txtPreamble->toPlainText();
01178   QStringList packages;
01179   bool moreDefinitions = false;
01180   int k;
01181   for (k = 0; k < cmds.size(); ++k) {
01182     if (curpreambletext.indexOf(cmds[k]) >= 0)
01183       continue; // this line is already included
01184 
01185     missingCmds->append(cmds[k]);
01186 
01187     QRegExp rx("\\\\usepackage.*\\{(\\w+)\\}");
01188     klfDbg(" regexp="<<rx.pattern()<<"; cmd for symbol: "<<cmds[k].trimmed());
01189     if (rx.exactMatch(cmds[k].trimmed())) {
01190       packages << rx.cap(1); // the package name
01191     } else {
01192       // not a package inclusion
01193       moreDefinitions = true;
01194     }
01195   }
01196   if (wantHtmlText)
01197     packages.replaceInStrings(QRegExp("^(.*)$"), QString("<b>\\1</b>"));
01198 
01199   QString requiredtext;
01200   if (packages.size()) {
01201     if (packages.size() == 1)
01202       requiredtext += tr("package %1",
01203                          "[[part of popup text, if one package only]]").arg(packages[0]);
01204     else
01205       requiredtext += tr("packages %1",
01206                          "[[part of popup text, if multiple packages]]").arg(packages.join(", "));
01207   }
01208   if (moreDefinitions)
01209     requiredtext += packages.size()
01210       ? tr(" and <i>some more definitions</i>",
01211            "[[part of hint popup text, when packages also need to be included]]")
01212       : tr("<i>some definitions</i>",
01213            "[[part of hint popup text, when no packages need to be included]]");
01214   if (!wantHtmlText)
01215     requiredtext.replace(QRegExp("<[^>]*>"), "");
01216 
01217   *guiText = requiredtext;
01218 }
01219 
01220 void KLFMainWin::slotNewSymbolTyped(const QString& symbol)
01221 {
01222   if (mPopup == NULL)
01223     mPopup = new KLFMainWinPopup(this);
01224 
01225   if (!klfconfig.UI.showHintPopups)
01226     return;
01227 
01228   QStringList cmds;
01229   QString requiredtext;
01230 
01231   getMissingCmdsFor(symbol, &cmds, &requiredtext);
01232 
01233   if (cmds.isEmpty()) // nothing to include
01234     return;
01235 
01236   QByteArray cmdsData = klfSaveVariantToText(QVariant(cmds));
01237   QString msgkey = "preambleCmdStringList:"+QString::fromLatin1(cmdsData);
01238   QUrl urlaction;
01239   urlaction.setScheme("klfaction");
01240   urlaction.setPath("/popup");
01241   QUrl urlactionClose = urlaction;
01242   urlaction.addQueryItem("preambleCmdStringList", QString::fromLatin1(cmdsData));
01243   urlactionClose.addQueryItem("removeMessageKey", msgkey);
01244   mPopup->addMessage(msgkey,
01245                      //"[<a href=\""+urlactionClose.toEncoded()+"\">"
01246                      //"<img border=\"0\" src=\":/pics/smallclose.png\"></a>] - "+
01247                      tr("Symbol <tt>%3</tt> may require <a href=\"%1\">%2</a>.")
01248                      .arg(urlaction.toEncoded(), requiredtext, symbol) );
01249   mPopup->show();
01250   mPopup->raise();
01251 }
01252 void KLFMainWin::slotPopupClose()
01253 {
01254   if (mPopup != NULL) {
01255     delete mPopup;
01256     mPopup = NULL;
01257   }
01258 }
01259 void KLFMainWin::slotPopupAction(const QUrl& url)
01260 {
01261   klfDbg("url="<<url.toEncoded());
01262   if (url.hasQueryItem("preambleCmdStringList")) {
01263     // include the given package
01264     QByteArray data = url.queryItemValue("preambleCmdStringList").toLatin1();
01265     klfDbg("data="<<data);
01266     QStringList cmds = klfLoadVariantFromText(data, "QStringList").toStringList();
01267     klfDbg("ensuring CMDS="<<cmds);
01268     int k;
01269     for (k = 0; k < cmds.size(); ++k) {
01270       slotEnsurePreambleCmd(cmds[k]);
01271     }
01272     mPopup->removeMessage("preambleCmdStringList:"+QString::fromLatin1(data));
01273     if (!mPopup->hasMessages())
01274       slotPopupClose();
01275     return;
01276   }
01277   if (url.hasQueryItem("acceptAll")) {
01278     slotPopupAcceptAll();
01279     return;
01280   }
01281   if (url.hasQueryItem("removeMessageKey")) {
01282     QString key = url.queryItemValue("removeMessageKey");
01283     mPopup->removeMessage(key);
01284     if (!mPopup->hasMessages())
01285       slotPopupClose();
01286     return;
01287   }
01288   if (url.hasQueryItem("configDontShow")) {
01289     // don't show popups
01290     slotPopupClose();
01291     klfconfig.UI.showHintPopups = false;
01292     saveSettings();
01293     return;
01294   }
01295 }
01296 void KLFMainWin::slotPopupAcceptAll()
01297 {
01298   if (mPopup == NULL)
01299     return;
01300 
01301   // accept all messages, based on their key
01302   QStringList keys = mPopup->messageKeys();
01303   int k;
01304   for (k = 0; k < keys.size(); ++k) {
01305     QString s = keys[k];
01306     if (s.startsWith("preambleCmdStringList:")) {
01307       QByteArray data = s.mid(strlen("preambleCmdStringList:")).toLatin1();
01308       QStringList cmds = klfLoadVariantFromText(data, "QStringList").toStringList();
01309       int k;
01310       for (k = 0; k < cmds.size(); ++k) {
01311         slotEnsurePreambleCmd(cmds[k]);
01312       }
01313       continue;
01314     }
01315     qWarning()<<KLF_FUNC_NAME<<": Unknown message key: "<<s;
01316   }
01317   slotPopupClose();
01318 }
01319 
01320 void KLFMainWin::slotEditorContextMenuInsertActions(const QPoint& pos, QList<QAction*> *actionList)
01321 {
01322   KLFLatexEdit *latexEdit = qobject_cast<KLFLatexEdit*>(sender());
01323   KLF_ASSERT_NOT_NULL( latexEdit, "KLFLatexEdit sender is NULL!", return ) ;
01324 
01325   // try to determine if we clicked on a symbol, and suggest to include the corresponding package
01326 
01327   QTextCursor cur = latexEdit->cursorForPosition(pos);
01328   QString text = latexEdit->toPlainText();
01329   int curpos = cur.position();
01330 
01331   QRegExp rxSym("\\\\(\\w+|.)");
01332   int i = text.lastIndexOf(rxSym, curpos); // search backwards from curpos
01333   if (i >= 0) {
01334     // matched somewhere before in text. See if we clicked on it
01335     int len = rxSym.matchedLength();
01336     QString symbol = text.mid(i, len);
01337     QStringList cmds;
01338     QString guitext;
01339     getMissingCmdsFor(symbol, &cmds, &guitext, false);
01340     if (cmds.size()) {
01341       QAction * aInsCmds = new QAction(latexEdit);
01342       aInsCmds->setText(tr("Include missing definitions for %1").arg(symbol));
01343       aInsCmds->setData(QVariant(cmds));
01344       connect(aInsCmds, SIGNAL(triggered()), this, SLOT(slotInsertMissingPackagesFromActionSender()));
01345       *actionList << aInsCmds;
01346     }
01347   }
01348 
01349   QAction *insertSymbolAction = new QAction(QIcon(":/pics/symbols.png"),
01350                                             tr("Insert Symbol ...", "[[context menu entry]]"), latexEdit);
01351   connect(insertSymbolAction, SIGNAL(triggered()), this, SLOT(slotSymbols()));
01352   *actionList << insertSymbolAction;
01353 }
01354 
01355 
01356 void KLFMainWin::slotInsertMissingPackagesFromActionSender()
01357 {
01358   QAction * a = qobject_cast<QAction*>(sender());
01359   if (a == NULL) {
01360     qWarning()<<KLF_FUNC_NAME<<": NULL QAction sender!";
01361     return;
01362   }
01363   QVariant data = a->data();
01364   QStringList cmds = data.toStringList();
01365   int k;
01366   for (k = 0; k < cmds.size(); ++k) {
01367     slotEnsurePreambleCmd(cmds[k]);
01368   }
01369 }
01370 
01371 
01372 
01373 void KLFMainWin::slotSymbolsButtonRefreshState(bool on)
01374 {
01375   u->btnSymbols->setChecked(on);
01376 }
01377 
01378 void KLFMainWin::showAbout()
01379 {
01380   mAboutDialog->show();
01381 }
01382 
01383 void KLFMainWin::showWhatsNew()
01384 {
01385   // center the widget on the desktop
01386   QSize desktopSize = QApplication::desktop()->screenGeometry(this).size();
01387   QSize wS = mWhatsNewDialog->sizeHint();
01388   mWhatsNewDialog->move(desktopSize.width()/2 - wS.width()/2,
01389                         desktopSize.height()/2 - wS.height()/2);
01390   mWhatsNewDialog->show();
01391 }
01392 
01393 void KLFMainWin::showSettingsHelpLinkAction(const QUrl& link)
01394 {
01395   klfDbg( ": link="<<link ) ;
01396   mSettingsDialog->show();
01397   mSettingsDialog->showControl(link.queryItemValue("control"));
01398 }
01399 
01400 void KLFMainWin::helpLinkAction(const QUrl& link)
01401 {
01402   klfDbg( ": Link is "<<link<<"; scheme="<<link.scheme()<<"; path="<<link.path()
01403           <<"; queryItems="<<link.queryItems() ) ;
01404 
01405   if (link.scheme() == "http") {
01406     // web link
01407     QDesktopServices::openUrl(link);
01408     return;
01409   }
01410   if (link.scheme() == "klfaction") {
01411     // find the help link action(s) that is (are) associated with this link
01412     bool calledOne = false;
01413     int k;
01414     for (k = 0; k < mHelpLinkActions.size(); ++k) {
01415       if (mHelpLinkActions[k].path == link.path()) {
01416         // got one
01417         if (mHelpLinkActions[k].wantParam)
01418           QMetaObject::invokeMethod(mHelpLinkActions[k].reciever,
01419                                     mHelpLinkActions[k].memberFunc.constData(),
01420                                     Qt::QueuedConnection, Q_ARG(QUrl, link));
01421         else
01422           QMetaObject::invokeMethod(mHelpLinkActions[k].reciever,
01423                                     mHelpLinkActions[k].memberFunc.constData(),
01424                                     Qt::QueuedConnection);
01425 
01426         calledOne = true;
01427       }
01428     }
01429     if (!calledOne) {
01430       qWarning()<<KLF_FUNC_NAME<<": no action found for link="<<link;
01431     }
01432     return;
01433   }
01434   qWarning()<<KLF_FUNC_NAME<<"("<<link<<"): Unrecognized link scheme!";
01435 }
01436 
01437 void KLFMainWin::addWhatsNewText(const QString& htmlSnipplet)
01438 {
01439   mWhatsNewDialog->addExtraText(htmlSnipplet);
01440 }
01441 
01442 
01443 void KLFMainWin::registerHelpLinkAction(const QString& path, QObject *object, const char * member,
01444                                         bool wantUrlParam)
01445 {
01446   mHelpLinkActions << HelpLinkAction(path, object, member, wantUrlParam);
01447 }
01448 
01449 
01450 void KLFMainWin::registerOutputSaver(KLFAbstractOutputSaver *outputsaver)
01451 {
01452   KLF_ASSERT_NOT_NULL( outputsaver, "Refusing to register NULL Output Saver object!",  return ) ;
01453 
01454   pOutputSavers.append(outputsaver);
01455 }
01456 
01457 void KLFMainWin::unregisterOutputSaver(KLFAbstractOutputSaver *outputsaver)
01458 {
01459   pOutputSavers.removeAll(outputsaver);
01460 }
01461 
01462 void KLFMainWin::registerDataOpener(KLFAbstractDataOpener *dataopener)
01463 {
01464   KLF_ASSERT_NOT_NULL( dataopener, "Refusing to register NULL Data Opener object!",  return ) ;
01465 
01466   pDataOpeners.append(dataopener);
01467 }
01468 void KLFMainWin::unregisterDataOpener(KLFAbstractDataOpener *dataopener)
01469 {
01470   pDataOpeners.removeAll(dataopener);
01471 }
01472 
01473 
01474 void KLFMainWin::setWidgetStyle(const QString& qtstyle)
01475 {
01476   //  qDebug("setWidgetStyle(\"%s\")", qPrintable(qtstyle));
01477   if (_widgetstyle == qtstyle) {
01478     //    qDebug("This style is already applied.");
01479     return;
01480   }
01481   if (qtstyle.isNull()) {
01482     // setting a null style resets internal widgetstyle name...
01483     _widgetstyle = QString::null;
01484     return;
01485   }
01486   QStringList stylelist = QStyleFactory::keys();
01487   if (stylelist.indexOf(qtstyle) == -1) {
01488     qWarning("Bad Style: %s. List of possible styles are:", qPrintable(qtstyle));
01489     int k;
01490     for (k = 0; k < stylelist.size(); ++k)
01491       qWarning("\t%s", qPrintable(stylelist[k]));
01492     return;
01493   }
01494   //  qDebug("Setting the style %s. are we visible?=%d", qPrintable(qtstyle), (int)QWidget::isVisible());
01495   QStyle *s = QStyleFactory::create(qtstyle);
01496   //  qDebug("Got style ptr=%p", (void*)s);
01497   if ( ! s ) {
01498     qWarning("Can't instantiate style %s!", qPrintable(qtstyle));
01499     return;
01500   }
01501   _widgetstyle = qtstyle;
01502   qApp->setStyle( s );
01503 }
01504 
01505 void KLFMainWin::setQuitOnClose(bool quitOnClose)
01506 {
01507   _ignore_close_event = ! quitOnClose;
01508 }
01509 
01510 
01511 void KLFMainWin::quit()
01512 {
01513   KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
01514 
01515   hide();
01516 
01517   if (mLibBrowser)
01518     mLibBrowser->hide();
01519   if (mLatexSymbols)
01520     mLatexSymbols->hide();
01521   if (mStyleManager)
01522     mStyleManager->hide();
01523   if (mSettingsDialog)
01524     mSettingsDialog->hide();
01525   qApp->quit();
01526 }
01527 
01528 bool KLFMainWin::event(QEvent *e)
01529 {
01530   klfDbg("e->type() == "<<e->type());
01531 
01532   if (e->type() == QEvent::ApplicationFontChange) {
01533     klfDbg("Application font change.") ;
01534     if (klfconfig.UI.useSystemAppFont)
01535       klfconfig.UI.applicationFont = QApplication::font(); // refresh the font setting...
01536   }
01537   
01538   return QWidget::event(e);
01539 }
01540 
01541 void KLFMainWin::childEvent(QChildEvent *e)
01542 {
01543   QObject *child = e->child();
01544   if (e->type() == QEvent::ChildAdded && child->isWidgetType()) {
01545     QWidget *w = qobject_cast<QWidget*>(child);
01546     if (w->windowFlags() & Qt::Window) {
01547       // note that all Qt::Tool, Qt::SplashScreen etc. all have the Qt::Window bit set, but
01548       // not Qt::Widget (!)
01549       pWindowList.append(w);
01550       klfDbg( ": Added child "<<w<<" ("<<w->objectName()<<")" ) ;
01551     }
01552   } else if (e->type() == QEvent::ChildRemoved && child->isWidgetType()) {
01553     QWidget *w = qobject_cast<QWidget*>(child);
01554     int k;
01555     if ((k = pWindowList.indexOf(w)) >= 0) {
01556       klfDbg( ": Removing child "<<w<<" ("<<w->objectName()<<")"
01557               <<" at position k="<<k ) ;
01558       pWindowList.removeAt(k);
01559     }
01560   }
01561 
01562   QWidget::childEvent(e);
01563 }
01564 
01565 bool KLFMainWin::eventFilter(QObject *obj, QEvent *e)
01566 {
01567 
01568   // even with QShortcuts, we still need this event handler (why?)
01569   if (obj == u->txtLatex) {
01570     if (e->type() == QEvent::KeyPress) {
01571       QKeyEvent *ke = (QKeyEvent*) e;
01572       if (ke->key() == Qt::Key_Return &&
01573           (QApplication::keyboardModifiers() == Qt::ShiftModifier ||
01574            QApplication::keyboardModifiers() == Qt::ControlModifier)) {
01575         slotEvaluate();
01576         return true;
01577       }
01578       if (mPopup != NULL && ke->key() == Qt::Key_Return &&
01579           QApplication::keyboardModifiers() == Qt::AltModifier) {
01580         slotPopupAcceptAll();
01581         return true;
01582       }
01583       if (mPopup != NULL && ke->key() == Qt::Key_Escape) {
01584         slotPopupClose();
01585         return true;
01586       }
01587       if (ke->key() == Qt::Key_F9) {
01588         slotExpand(true);
01589         u->tabsOptions->setCurrentWidget(u->tabLatexImage);
01590         u->txtPreamble->setFocus();
01591         return true;
01592       }
01593     }
01594   }
01595   if (obj == u->txtLatex || obj == u->btnEvaluate) {
01596     if (e->type() == QEvent::KeyPress) {
01597       QKeyEvent *ke = (QKeyEvent*) e;
01598       QKeySequence seq = QKeySequence(ke->key() | ke->modifiers());
01599       if (seq.matches(QKeySequence::Copy)) {
01600         // copy key shortcut. Check if editor received the event, and if there is a selection
01601         // in the editor. If there is a selection, let the editor copy it to clipboard. Otherwise
01602         // we will copy our output
01603         if (/*obj == u->txtLatex &&*/ u->txtLatex->textCursor().hasSelection()) {
01604           u->txtLatex->copy();
01605           return true;
01606         } else {
01607           slotCopy();
01608           return true;
01609         }
01610       }
01611     }
01612   }
01613 
01614   // ----
01615   if ( obj->isWidgetType() && (e->type() == QEvent::Hide || e->type() == QEvent::Show) ) {
01616     // shown/hidden windows: save/restore geometry
01617     int k = pWindowList.indexOf(qobject_cast<QWidget*>(obj));
01618     if (k >= 0) {
01619       QWidget *w = qobject_cast<QWidget*>(obj);
01620       // this widget is one of our monitored top-level children.
01621       if (e->type() == QEvent::Hide && !((QHideEvent*)e)->spontaneous()) {
01622         if (pLastWindowShownStatus[w])
01623           pLastWindowGeometries[w] = klf_get_window_geometry(w);
01624         pLastWindowShownStatus[w] = false;
01625       } else if (e->type() == QEvent::Show && !((QShowEvent*)e)->spontaneous()) {
01626         pLastWindowShownStatus[w] = true;
01627         klf_set_window_geometry(w, pLastWindowGeometries[w]);
01628       }
01629     }
01630   }
01631   // ----
01632   if ( obj == mLibBrowser && (e->type() == QEvent::Hide || e->type() == QEvent::Show) ) {
01633     slotLibraryButtonRefreshState(mLibBrowser->isVisible());
01634   }
01635   if ( obj == mLatexSymbols && (e->type() == QEvent::Hide || e->type() == QEvent::Show) ) {
01636     slotSymbolsButtonRefreshState(mLatexSymbols->isVisible());
01637   }
01638 
01639   // ----
01640   if ( obj == QApplication::instance() && e->type() == QEvent::FileOpen ) {
01641     // open a file
01642     openFile(((QFileOpenEvent*)e)->file());
01643     return true;
01644   }
01645 
01646   // ----
01647   if ( (obj == u->btnCopy || obj == u->btnDrag) && e->type() == QEvent::ToolTip ) {
01648     QString tooltipText;
01649     if (obj == u->btnCopy) {
01650       tooltipText = tr("Copy the formula to the clipboard. Current export profile: %1")
01651         .arg(KLFMimeExportProfile::findExportProfile(klfconfig.UI.copyExportProfile).description());
01652     } else if (obj == u->btnDrag) {
01653       tooltipText = tr("Click and keep mouse button pressed to drag your formula to an other application. "
01654                        "Current export profile: %1")
01655         .arg(KLFMimeExportProfile::findExportProfile(klfconfig.UI.dragExportProfile).description());
01656     }
01657     QToolTip::showText(((QHelpEvent*)e)->globalPos(), tooltipText, qobject_cast<QWidget*>(obj));
01658     return true;
01659   }
01660 
01661   return QWidget::eventFilter(obj, e);
01662 }
01663 
01664 
01665 void KLFMainWin::refreshAllWindowStyleSheets()
01666 {
01667   int k;
01668   for (k = 0; k < pWindowList.size(); ++k)
01669     pWindowList[k]->setStyleSheet(pWindowList[k]->styleSheet());
01670   // me too!
01671   setStyleSheet(styleSheet());
01672 }
01673 
01674 
01675 QHash<QWidget*,bool> KLFMainWin::currentWindowShownStatus(bool mainWindowToo)
01676 {
01677   QHash<QWidget*,bool> status;
01678   if (mainWindowToo)
01679     status[this] = isVisible();
01680   int k;
01681   for (k = 0; k < pWindowList.size(); ++k)
01682     status[pWindowList[k]] = pWindowList[k]->isVisible();
01683   return status;
01684 }
01685 QHash<QWidget*,bool> KLFMainWin::prepareAllWindowShownStatus(bool visibleStatus, bool mainWindowToo)
01686 {
01687   QHash<QWidget*,bool> status;
01688   if (mainWindowToo)
01689     status[this] = visibleStatus;
01690   int k;
01691   for (k = 0; k < pWindowList.size(); ++k)
01692     status[pWindowList[k]] = visibleStatus;
01693   return status;
01694 }
01695 
01696 void KLFMainWin::setWindowShownStatus(const QHash<QWidget*,bool>& shownStatus)
01697 {
01698   for (QHash<QWidget*,bool>::const_iterator it = shownStatus.begin(); it != shownStatus.end(); ++it)
01699     QMetaObject::invokeMethod(it.key(), "setVisible", Qt::QueuedConnection, Q_ARG(bool, it.value()));
01700 }
01701 
01702 
01703 void KLFMainWin::hideEvent(QHideEvent *e)
01704 {
01705   if ( ! e->spontaneous() ) {
01706     pSavedWindowShownStatus = currentWindowShownStatus(false);
01707     pLastWindowGeometries[this] = klf_get_window_geometry(this);
01708     setWindowShownStatus(prepareAllWindowShownStatus(false, false)); // hide all windows
01709   }
01710 
01711   QWidget::hideEvent(e);
01712 }
01713 
01714 void KLFMainWin::showEvent(QShowEvent *e)
01715 {
01716   if ( _firstshow ) {
01717     _firstshow = false;
01718     // if it's the first time we're run, 
01719     // show the what's new if needed.
01720     if ( klfconfig.Core.thisVersionMajMinFirstRun ) {
01721       QMetaObject::invokeMethod(this, "showWhatsNew", Qt::QueuedConnection);
01722     }
01723   }
01724 
01725   if ( ! e->spontaneous() ) {
01726     // restore shown windows ...
01727     if (pLastWindowGeometries.contains(this))
01728       klf_set_window_geometry(this, pLastWindowGeometries[this]);
01729     setWindowShownStatus(pSavedWindowShownStatus);
01730   }
01731 
01732   QWidget::showEvent(e);
01733 }
01734 
01735 
01736 void KLFMainWin::timerEvent(QTimerEvent *e)
01737 {
01738   if (e->timerId() == pExportMsgLabelTimerId) {
01739     int total = mExportMsgLabel->property("timeTotal").toInt();
01740     int remaining = mExportMsgLabel->property("timeRemaining").toInt();
01741     int interval = mExportMsgLabel->property("timeInterval").toInt();
01742 
01743     int fadepercent = (100 * remaining / total) * 3; // 0 ... 300
01744     if (fadepercent < 100 && fadepercent >= 0) {
01745       QPalette pal = mExportMsgLabel->property("defaultPalette").value<QPalette>();
01746       QColor c = pal.color(QPalette::Window);
01747       c.setAlpha(c.alpha() * fadepercent / 100);
01748       pal.setColor(QPalette::Window, c);
01749       QColor c2 = pal.color(QPalette::WindowText);
01750       c2.setAlpha(c2.alpha() * fadepercent / 100);
01751       pal.setColor(QPalette::WindowText, c2);
01752       mExportMsgLabel->setPalette(pal);
01753     }
01754 
01755     remaining -= interval;
01756     if (remaining < 0) {
01757       mExportMsgLabel->hide();
01758       killTimer(pExportMsgLabelTimerId);
01759       pExportMsgLabelTimerId = -1;
01760     } else {
01761       mExportMsgLabel->setProperty("timeRemaining", QVariant(remaining));
01762     }
01763   }
01764 }
01765 
01766 
01767 
01768 void KLFMainWin::alterSetting(altersetting_which which, int ivalue)
01769 {
01770   _settings_altered = true;
01771   switch (which) {
01772   case altersetting_LBorderOffset:
01773     _settings.lborderoffset = ivalue; break;
01774   case altersetting_TBorderOffset:
01775     _settings.tborderoffset = ivalue; break;
01776   case altersetting_RBorderOffset:
01777     _settings.rborderoffset = ivalue; break;
01778   case altersetting_BBorderOffset:
01779     _settings.bborderoffset = ivalue; break;
01780   case altersetting_OutlineFonts:
01781     _settings.outlineFonts = (bool)ivalue; break;
01782   default:
01783     break;
01784   }
01785 }
01786 void KLFMainWin::alterSetting(altersetting_which which, QString svalue)
01787 {
01788   _settings_altered = true;
01789   switch (which) {
01790   case altersetting_TempDir:
01791     _settings.tempdir = svalue; break;
01792   case altersetting_Latex:
01793     _settings.latexexec = svalue; break;
01794   case altersetting_Dvips:
01795     _settings.dvipsexec = svalue; break;
01796   case altersetting_Gs:
01797     _settings.gsexec = svalue; break;
01798   case altersetting_Epstopdf:
01799     _settings.epstopdfexec = svalue; break;
01800   default:
01801     break;
01802   }
01803 }
01804 
01805 
01806 KLFLatexEdit *KLFMainWin::latexEdit()
01807 {
01808   return u->txtLatex;
01809 }
01810 KLFLatexSyntaxHighlighter * KLFMainWin::syntaxHighlighter()
01811 {
01812   return u->txtLatex->syntaxHighlighter();
01813 }
01814 KLFLatexSyntaxHighlighter * KLFMainWin::preambleSyntaxHighlighter()
01815 {
01816   return u->txtPreamble->syntaxHighlighter();
01817 }
01818 
01819 
01820 
01821 
01822 
01823 void KLFMainWin::applySettings(const KLFBackend::klfSettings& s)
01824 {
01825   _settings = s;
01826   _settings_altered = false;
01827 }
01828 
01829 void KLFMainWin::displayError(const QString& error)
01830 {
01831   QMessageBox::critical(this, tr("Error"), error);
01832 }
01833 
01834 
01835 void KLFMainWin::updatePreviewBuilderThreadInput()
01836 {
01837   bool reallyinputchanged = mPreviewBuilderThread->inputChanged(collectInput(false));
01838   if (reallyinputchanged) {
01839     _evaloutput_uptodate = false;
01840   }
01841 }
01842 
01843 void KLFMainWin::setTxtLatexFont(const QFont& f)
01844 {
01845   u->txtLatex->setFont(f);
01846 }
01847 void KLFMainWin::setTxtPreambleFont(const QFont& f)
01848 {
01849   u->txtPreamble->setFont(f);
01850 }
01851 
01852 void KLFMainWin::showRealTimePreview(const QImage& preview, bool latexerror)
01853 {
01854   klfDbg("preview.size=" << preview.size()<< "  latexerror=" << latexerror);
01855   if (_evaloutput_uptodate)
01856     return;
01857 
01858   if (latexerror)
01859     u->lblOutput->displayError(/*labelenabled:*/false);
01860   else
01861     u->lblOutput->display(preview, preview, false);
01862 
01863 }
01864 
01865 KLFBackend::klfInput KLFMainWin::collectInput(bool final)
01866 {
01867   // KLFBackend input
01868   KLFBackend::klfInput input;
01869 
01870   input.latex = u->txtLatex->toPlainText();
01871   if (u->chkMathMode->isChecked()) {
01872     input.mathmode = u->cbxMathMode->currentText();
01873     if (final && u->cbxMathMode->findText(input.mathmode) == -1) {
01874       u->cbxMathMode->addItem(input.mathmode);
01875       klfconfig.UI.customMathModes.append(input.mathmode);
01876     }
01877   } else {
01878     input.mathmode = "...";
01879   }
01880   input.preamble = u->txtPreamble->toPlainText();
01881   input.fg_color = u->colFg->color().rgb();
01882   if (u->chkBgTransparent->isChecked() == false)
01883     input.bg_color = u->colBg->color().rgb();
01884   else
01885     input.bg_color = qRgba(255, 255, 255, 0);
01886 
01887   input.dpi = u->spnDPI->value();
01888 
01889   return input;
01890 }
01891 
01892 void KLFMainWin::slotEvaluate()
01893 {
01894   // KLFBackend input
01895   KLFBackend::klfInput input;
01896 
01897   u->btnEvaluate->setEnabled(false); // don't allow user to click us while we're not done, and
01898   //                                 additionally this gives visual feedback to the user
01899 
01900   input = collectInput(true);
01901 
01902   KLFBackend::klfSettings settings = _settings;
01903   // see if we need to override settings
01904   if (u->gbxOverrideMargins->isChecked()) {
01905     settings.tborderoffset = u->spnMarginTop->valueInRefUnit();
01906     settings.rborderoffset = u->spnMarginRight->valueInRefUnit();
01907     settings.bborderoffset = u->spnMarginBottom->valueInRefUnit();
01908     settings.lborderoffset = u->spnMarginLeft->valueInRefUnit();
01909   }
01910 
01911   // and GO !
01912   _output = KLFBackend::getLatexFormula(input, settings);
01913 
01914   if (_output.status < 0) {
01915     QString comment = "";
01916     bool showSettingsPaths = false;
01917     if (_output.status == KLFERR_NOLATEXPROG ||
01918         _output.status == KLFERR_NODVIPSPROG ||
01919         _output.status == KLFERR_NOGSPROG ||
01920         _output.status == KLFERR_NOEPSTOPDFPROG) {
01921       comment = "\n"+tr("Are you sure you configured your system paths correctly in the settings dialog ?");
01922       showSettingsPaths = true;
01923     }
01924     QMessageBox::critical(this, tr("Error"), _output.errorstr+comment);
01925     u->lblOutput->displayClear();
01926     u->frmOutput->setEnabled(false);
01927     if (showSettingsPaths) {
01928       mSettingsDialog->show();
01929       mSettingsDialog->showControl(KLFSettings::ExecutablePaths);
01930     }
01931   }
01932   if (_output.status > 0) {
01933     KLFProgErr::showError(this, _output.errorstr);
01934     u->frmOutput->setEnabled(false);
01935   }
01936   if (_output.status == 0) {
01937     // ALL OK
01938     _evaloutput_uptodate = true;
01939 
01940     QPixmap sc;
01941     // scale to view size (klfconfig.UI.labelOutputFixedSize)
01942     QSize fsize = klfconfig.UI.labelOutputFixedSize;
01943     if (_output.result.width() > fsize.width() || _output.result.height() > fsize.height())
01944       sc = QPixmap::fromImage(_output.result.scaled(fsize, Qt::KeepAspectRatio, Qt::SmoothTransformation));
01945     else
01946       sc = QPixmap::fromImage(_output.result);
01947 
01948     QSize goodsize = _output.result.size();
01949     QImage tooltipimg = _output.result;
01950     if ( klfconfig.UI.previewTooltipMaxSize != QSize(0, 0) && // QSize(0,0) meaning no resize
01951          ( tooltipimg.width() > klfconfig.UI.previewTooltipMaxSize.width() ||
01952            tooltipimg.height() > klfconfig.UI.previewTooltipMaxSize.height() ) ) {
01953       tooltipimg =
01954         _output.result.scaled(klfconfig.UI.previewTooltipMaxSize, Qt::KeepAspectRatio,
01955                               Qt::SmoothTransformation);
01956     }
01957     emit evaluateFinished(_output);
01958     u->lblOutput->display(sc.toImage(), tooltipimg, true);
01959     u->frmOutput->setEnabled(true);
01960 
01961     KLFLibEntry newentry = KLFLibEntry(input.latex, QDateTime::currentDateTime(), sc.toImage(),
01962                                        currentStyle());
01963     // check that this is not already the last entry. Perform a query to check this.
01964     bool needInsertThisEntry = true;
01965     KLFLibResourceEngine::Query query;
01966     query.matchCondition = KLFLib::EntryMatchCondition::mkMatchAll();
01967     query.skip = 0;
01968     query.limit = 1;
01969     query.orderPropId = KLFLibEntry::DateTime;
01970     query.orderDirection = Qt::DescendingOrder;
01971     query.wantedEntryProperties =
01972       QList<int>() << KLFLibEntry::Latex << KLFLibEntry::Style << KLFLibEntry::Category << KLFLibEntry::Tags;
01973     KLFLibResourceEngine::QueryResult queryResult(KLFLibResourceEngine::QueryResult::FillRawEntryList);
01974     int num = mHistoryLibResource->query(mHistoryLibResource->defaultSubResource(), query, &queryResult);
01975     if (num >= 1) {
01976       KLFLibEntry e = queryResult.rawEntryList[0];
01977       if (e.latex() == newentry.latex() &&
01978           e.category() == newentry.category() &&
01979           e.tags() == newentry.tags() &&
01980           e.style() == newentry.style())
01981         needInsertThisEntry = false;
01982     }
01983 
01984     if (needInsertThisEntry) {
01985       int eid = mHistoryLibResource->insertEntry(newentry);
01986       bool result = (eid >= 0);
01987       if ( ! result && mHistoryLibResource->locked() ) {
01988         int r = QMessageBox::warning(this, tr("Warning"),
01989                                      tr("Can't add the item to history library because the history "
01990                                         "resource is locked. Do you want to unlock it?"),
01991                                      QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes);
01992         if (r == QMessageBox::Yes) {
01993           mHistoryLibResource->setLocked(false);
01994           result = mHistoryLibResource->insertEntry(newentry); // retry inserting entry
01995         }
01996       }
01997       uint fl = mHistoryLibResource->supportedFeatureFlags();
01998       if ( ! result && (fl & KLFLibResourceEngine::FeatureSubResources) &&
01999            (fl & KLFLibResourceEngine::FeatureSubResourceProps) &&
02000            mHistoryLibResource->subResourceProperty(mHistoryLibResource->defaultSubResource(),
02001                                                     KLFLibResourceEngine::SubResPropLocked).toBool() ) {
02002         int r = QMessageBox::warning(this, tr("Warning"),
02003                                      tr("Can't add the item to history library because the history "
02004                                         "sub-resource is locked. Do you want to unlock it?"),
02005                                      QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes);
02006         if (r == QMessageBox::Yes) {
02007           mHistoryLibResource->setSubResourceProperty(mHistoryLibResource->defaultSubResource(),
02008                                                       KLFLibResourceEngine::SubResPropLocked, false);
02009           result = mHistoryLibResource->insertEntry(newentry); // retry inserting entry
02010       }
02011       }
02012       if ( ! result && mHistoryLibResource->isReadOnly() ) {
02013         qWarning("KLFMainWin::slotEvaluate: History resource is READ-ONLY !! Should NOT!");
02014         QMessageBox::critical(this, tr("Error"),
02015                               tr("Can't add the item to history library because the history "
02016                                  "resource is opened in read-only mode. This should not happen! "
02017                                  "You will need to manually copy and paste your Latex code somewhere "
02018                                  "else to save it."),
02019                             QMessageBox::Ok, QMessageBox::Ok);
02020       }
02021       if ( ! result ) {
02022         qWarning("KLFMainWin::slotEvaluate: History resource couldn't be written!");
02023         QMessageBox::critical(this, tr("Error"),
02024                               tr("An error occurred when trying to write the new entry into the "
02025                                  "history resource!"
02026                                  "You will need to manually copy and paste your Latex code somewhere "
02027                                  "else to save it."),
02028                             QMessageBox::Ok, QMessageBox::Ok);
02029       }
02030     }
02031   }
02032 
02033   u->btnEvaluate->setEnabled(true); // re-enable our button
02034   u->btnEvaluate->setFocus();
02035 }
02036 
02037 void KLFMainWin::slotClearLatex()
02038 {
02039   u->txtLatex->clearLatex();
02040 }
02041 void KLFMainWin::slotClearAll()
02042 {
02043   slotClearLatex();
02044   loadDefaultStyle();
02045 }
02046 
02047 
02048 void KLFMainWin::slotLibrary(bool showlib)
02049 {
02050   klfDbg("showlib="<<showlib) ;
02051   mLibBrowser->setShown(showlib);
02052   if (showlib) {
02053     // already shown, raise the window
02054     mLibBrowser->activateWindow();
02055     mLibBrowser->raise();
02056   }
02057 }
02058 
02059 void KLFMainWin::slotSymbols(bool showsymbs)
02060 {
02061   mLatexSymbols->setShown(showsymbs);
02062   slotSymbolsButtonRefreshState(showsymbs);
02063   mLatexSymbols->activateWindow();
02064   mLatexSymbols->raise();
02065 }
02066 
02067 void KLFMainWin::slotExpandOrShrink()
02068 {
02069   if (u->frmDetails->isVisible()) {
02070     u->frmDetails->hide();
02071     setFixedSize(_shrinkedsize);
02072     //    adjustSize();
02073     u->btnExpand->setIcon(QIcon(":/pics/switchexpanded.png"));
02074   } else {
02075     setFixedSize(_expandedsize);
02076     u->frmDetails->show();
02077     //    adjustSize();
02078     u->btnExpand->setIcon(QIcon(":/pics/switchshrinked.png"));
02079   }
02080 }
02081 void KLFMainWin::slotExpand(bool expanded)
02082 {
02083   if (u->frmDetails->isVisible() == expanded)
02084     return; // nothing to change
02085   // change
02086   slotExpandOrShrink();
02087 }
02088 
02089 
02090 void KLFMainWin::slotSetLatex(const QString& latex)
02091 {
02092   u->txtLatex->setLatex(latex);
02093 }
02094 
02095 void KLFMainWin::slotSetMathMode(const QString& mathmode)
02096 {
02097   u->chkMathMode->setChecked(mathmode.simplified() != "...");
02098   if (mathmode.simplified() != "...")
02099     u->cbxMathMode->setEditText(mathmode);
02100 }
02101 
02102 void KLFMainWin::slotSetPreamble(const QString& preamble)
02103 {
02104   u->txtPreamble->setLatex(preamble);
02105 }
02106 
02107 void KLFMainWin::slotEnsurePreambleCmd(const QString& line)
02108 {
02109   QTextCursor c = u->txtPreamble->textCursor();
02110   //  qDebug("Begin preamble edit: preamble text is %s", qPrintable(u->txtPreamble->toPlainText()));
02111   c.beginEditBlock();
02112   c.movePosition(QTextCursor::End);
02113 
02114   QString preambletext = u->txtPreamble->toPlainText();
02115   if (preambletext.indexOf(line) == -1) {
02116     QString addtext = "";
02117     if (preambletext.length() > 0 &&
02118         preambletext[preambletext.length()-1] != '\n')
02119       addtext = "\n";
02120     addtext += line;
02121     c.insertText(addtext);
02122     preambletext += addtext;
02123   }
02124 
02125   c.endEditBlock();
02126 }
02127 
02128 void KLFMainWin::slotSetDPI(int DPI)
02129 {
02130   u->spnDPI->setValue(DPI);
02131 }
02132 
02133 void KLFMainWin::slotSetFgColor(const QColor& fg)
02134 {
02135   u->colFg->setColor(fg);
02136 }
02137 void KLFMainWin::slotSetFgColor(const QString& s)
02138 {
02139   QColor fgcolor;
02140   fgcolor.setNamedColor(s);
02141   slotSetFgColor(fgcolor);
02142 }
02143 void KLFMainWin::slotSetBgColor(const QColor& bg)
02144 {
02145   u->colBg->setColor(bg);
02146 }
02147 void KLFMainWin::slotSetBgColor(const QString& s)
02148 {
02149   QColor bgcolor;
02150   if (s == "-")
02151     bgcolor.setRgb(255, 255, 255, 0); // white transparent
02152   else
02153     bgcolor.setNamedColor(s);
02154   slotSetBgColor(bgcolor);
02155 }
02156 
02157 void KLFMainWin::slotEvaluateAndSave(const QString& output, const QString& format)
02158 {
02159   if ( u->txtLatex->toPlainText().isEmpty() )
02160     return;
02161 
02162   slotEvaluate();
02163 
02164   if ( ! output.isEmpty() ) {
02165     if ( _output.result.isNull() ) {
02166       QMessageBox::critical(this, tr("Error"), tr("There is no image to save."));
02167     } else {
02168       KLFBackend::saveOutputToFile(_output, output, format.trimmed().toUpper());
02169     }
02170   }
02171 
02172 }
02173 
02174 
02175 
02176 
02177 static QString find_list_agreement(const QStringList& a, const QStringList& b)
02178 {
02179   // returns the first element in a that is also in b, or a null QString() if there are no
02180   // common elements.
02181   int i, j;
02182   for (i = 0; i < a.size(); ++i)
02183     for (j = 0; j < b.size(); ++j)
02184       if (a[i] == b[j])
02185         return a[i];
02186   return QString();
02187 }
02188 
02189 bool KLFMainWin::canOpenFile(const QString& fileName)
02190 {
02191   KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
02192   klfDbg("file name="<<fileName) ;
02193   int k;
02194   for (k = 0; k < pDataOpeners.size(); ++k)
02195     if (pDataOpeners[k]->canOpenFile(fileName))
02196       return true;
02197   klfDbg("cannot open file.") ;
02198   return false;
02199 }
02200 bool KLFMainWin::canOpenData(const QByteArray& data)
02201 {
02202   KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
02203   klfDbg("data. length="<<data.size()) ;
02204   int k;
02205   for (k = 0; k < pDataOpeners.size(); ++k)
02206     if (pDataOpeners[k]->canOpenData(data))
02207       return true;
02208   klfDbg("cannot open data.") ;
02209   return false;
02210 }
02211 bool KLFMainWin::canOpenData(const QMimeData *mimeData)
02212 {
02213   KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
02214   QStringList formats = mimeData->formats();
02215   klfDbg("mime data. formats="<<formats) ;
02216 
02217   QString mimetype;
02218   int k;
02219   for (k = 0; k < pDataOpeners.size(); ++k) {
02220     mimetype = find_list_agreement(formats, pDataOpeners[k]->supportedMimeTypes());
02221     if (!mimetype.isEmpty())
02222       return true; // this opener can open the data
02223   }
02224   klfDbg("cannot open data: no appropriate opener found.") ;
02225   return false;
02226 }
02227 
02228 
02229 bool KLFMainWin::openFile(const QString& file)
02230 {
02231   KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02232   klfDbg("file="<<file) ;
02233   int k;
02234   for (k = 0; k < pDataOpeners.size(); ++k)
02235     if (pDataOpeners[k]->openFile(file))
02236       return true;
02237 
02238   QMessageBox::critical(this, tr("Error"), tr("Failed to load file %1.").arg(file));
02239 
02240   return false;
02241 }
02242 
02243 bool KLFMainWin::openFiles(const QStringList& fileList)
02244 {
02245   KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02246   klfDbg("file list="<<fileList) ;
02247   int k;
02248   bool result = true;
02249   for (k = 0; k < fileList.size(); ++k) {
02250     result = result && openFile(fileList[k]);
02251     klfDbg("Opened file "<<fileList[k]<<": result="<<result) ;
02252   }
02253   return result;
02254 }
02255 
02256 bool KLFMainWin::openData(const QMimeData *mimeData, bool *openerFound)
02257 {
02258   KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02259   klfDbg("mime data, formats="<<mimeData->formats()) ;
02260   int k;
02261   QString mimetype;
02262   QStringList fmts = mimeData->formats();
02263   if (openerFound != NULL)
02264     *openerFound = false;
02265   for (k = 0; k < pDataOpeners.size(); ++k) {
02266     mimetype = find_list_agreement(fmts, pDataOpeners[k]->supportedMimeTypes());
02267     if (!mimetype.isEmpty()) {
02268       if (openerFound != NULL)
02269         *openerFound = true;
02270       // mime types intersect.
02271       klfDbg("Opening mimetype "<<mimetype) ;
02272       QByteArray data = mimeData->data(mimetype);
02273       if (pDataOpeners[k]->openData(data, mimetype))
02274         return true;
02275     }
02276   }
02277 
02278   return false;
02279 }
02280 bool KLFMainWin::openData(const QByteArray& data)
02281 {
02282   KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02283   klfDbg("data, len="<<data.length()) ;
02284   int k;
02285   for (k = 0; k < pDataOpeners.size(); ++k)
02286     if (pDataOpeners[k]->openData(data, QString()))
02287       return true;
02288 
02289   return false;
02290 }
02291 
02292 
02293 bool KLFMainWin::openLibFiles(const QStringList& files, bool showLibrary)
02294 {
02295   KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02296   int k;
02297   bool imported = false;
02298   for (k = 0; k < files.size(); ++k) {
02299     bool ok = openLibFile(files[k], false);
02300     imported = imported || ok;
02301     klfDbg("imported file "<<files[k]<<": imported status is now "<<imported) ;
02302   }
02303   if (showLibrary && imported)
02304     slotLibrary(true);
02305   return imported;
02306 }
02307 
02308 bool KLFMainWin::openLibFile(const QString& fname, bool showLibrary)
02309 {
02310   KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
02311   klfDbg("fname="<<fname<<"; showLibrary="<<showLibrary) ;
02312   QUrl url = QUrl::fromLocalFile(fname);
02313   QString scheme = KLFLibBasicWidgetFactory::guessLocalFileScheme(fname);
02314   if (scheme.isEmpty()) {
02315     klfDbg("Can't guess scheme for file "<<fname) ;
02316     return false;
02317   }
02318   url.setScheme(scheme);
02319   klfDbg("url to open is "<<url) ;
02320   QStringList subreslist = KLFLibEngineFactory::listSubResources(url);
02321   if ( subreslist.isEmpty() ) {
02322     klfDbg("no sub-resources...") ;
02323     // error reading sub-resources, or sub-resources not supported
02324     return mLibBrowser->openResource(url);
02325   }
02326   klfDbg("subreslist is "<<subreslist);
02327   bool loaded = false;
02328   int k;
02329   for (k = 0; k < subreslist.size(); ++k) {
02330     QUrl url2 = url;
02331     url2.addQueryItem("klfDefaultSubResource", subreslist[k]);
02332     bool thisloaded =  mLibBrowser->openResource(url2);
02333     loaded = loaded || thisloaded;
02334   }
02335   if (showLibrary && loaded)
02336     slotLibrary(true);
02337   return loaded;
02338 }
02339 
02340 
02341 void KLFMainWin::setApplicationLocale(const QString& locale)
02342 {
02343   klf_reload_translations(qApp, locale);
02344 
02345   emit applicationLocaleChanged(locale);
02346 }
02347 
02348 void KLFMainWin::slotSetExportProfile(const QString& exportProfile)
02349 {
02350   if (klfconfig.UI.menuExportProfileAffectsCopy)
02351     klfconfig.UI.copyExportProfile = exportProfile;
02352   if (klfconfig.UI.menuExportProfileAffectsDrag)
02353     klfconfig.UI.dragExportProfile = exportProfile;
02354   saveSettings();
02355 }
02356 
02357 /*
02358 QMimeData * KLFMainWin::resultToMimeData(const QString& exportProfileName)
02359 {
02360   klfDbg("export profile: "<<exportProfileName);
02361   if ( _output.result.isNull() )
02362     return NULL;
02363 
02364   KLFMimeExportProfile p = KLFMimeExportProfile::findExportProfile(exportProfileName);
02365   QStringList mimetypes = p.mimeTypes();
02366 
02367   QMimeData *mimedata = new QMimeData;
02368   int k;
02369   for (k = 0; k < mimetypes.size(); ++k) {
02370     klfDbg("exporting "<<mimetypes[k]<<" ...");
02371     QString mimetype = mimetypes[k];
02372     KLFMimeExporter *exporter = KLFMimeExporter::mimeExporterLookup(mimetype);
02373     if (exporter == NULL) {
02374       qWarning()<<KLF_FUNC_NAME<<": Can't find an exporter for mime-type "<<mimetype<<".";
02375       continue;
02376     }
02377     QByteArray data = exporter->data(mimetype, _output);
02378     mimedata->setData(mimetype, data);
02379     klfDbg("exporting mimetype done");
02380   }
02381 
02382   klfDbg("got mime data.");
02383   return mimedata;
02384 }
02385 */
02386 
02387 
02388 void KLFMainWin::slotDrag()
02389 {
02390   if ( _output.result.isNull() )
02391     return;
02392 
02393   QDrag *drag = new QDrag(this);
02394   KLFMimeData *mime = new KLFMimeData(klfconfig.UI.dragExportProfile, _output);
02395 
02396   //  / ** \bug .... Temporary solution for mac os X ... * /
02397   //#ifdef Q_WS_MAC
02398   //  mime->setImageData(_output.result);
02399   //#endif
02400 
02401   drag->setMimeData(mime);
02402 
02403   QSize sz = QSize(200, 100);
02404   QImage img = _output.result;
02405   if (img.width() > sz.width() || img.height() > sz.height())
02406     img = img.scaled(sz, Qt::KeepAspectRatio, Qt::SmoothTransformation);
02407   // imprint the export type on the drag pixmap
02408   QString exportProfileText = KLFMimeExportProfile::findExportProfile(klfconfig.UI.dragExportProfile).description();
02409   { QPainter painter(&img);
02410     QFont smallfont = QFont("Helvetica", 8);
02411     smallfont.setPixelSize(12);
02412     painter.setFont(smallfont);
02413     painter.setRenderHint(QPainter::TextAntialiasing, false);
02414     QRect rall = QRect(QPoint(0,0), img.size());
02415     QRect bb = painter.boundingRect(rall, Qt::AlignBottom|Qt::AlignRight, exportProfileText);
02416     klfDbg("BB is "<<bb) ;
02417     painter.setPen(QPen(QColor(255,255,255,0), 0, Qt::NoPen));
02418     painter.fillRect(bb, QColor(150,150,150,128));
02419     painter.setPen(QPen(QColor(0,0,0), 1, Qt::SolidLine));
02420     painter.drawText(rall, Qt::AlignBottom|Qt::AlignRight, exportProfileText);
02421     /*
02422     QRect bb = painter.fontMetrics().boundingRect(exportProfileText);
02423     QPoint translate = QPoint(img.width(), img.height()) - bb.bottomRight();
02424     painter.setPen(QPen(QColor(255,255,255,0), 0, Qt::NoPen));
02425     painter.fillRect(translate.x(), translate.y(), bb.width(), bb.height(), QColor(128,128,128,128));
02426     painter.setPen(QPen(QColor(0,0,0), 1, Qt::SolidLine));
02427     painter.drawText(translate, exportProfileText);*/
02428   }
02429   QPixmap p = QPixmap::fromImage(img);
02430   drag->setPixmap(p);
02431   drag->setDragCursor(p, Qt::MoveAction);
02432   drag->setHotSpot(QPoint(p.width()/2, p.height()));
02433   drag->exec(Qt::CopyAction);
02434 }
02435 
02436 void KLFMainWin::slotCopy()
02437 {
02438 #ifdef Q_WS_WIN
02439   extern void klfWinClipboardCopy(HWND h, const QStringList& wintypes,
02440                                   const QList<QByteArray>& datalist);
02441 
02442   QString profilename = klfconfig.UI.copyExportProfile;
02443   KLFMimeExportProfile p = KLFMimeExportProfile::findExportProfile(profilename);
02444 
02445   QStringList mimetypes = p.mimeTypes();
02446   QStringList wintypes;
02447   QList<QByteArray> datalist;
02448 
02449   int k;
02450   for (k = 0; k < mimetypes.size(); ++k) {
02451     QString mimetype = mimetypes[k];
02452     QString wintype = p.respectiveWinType(k); // queries the exporter if needed
02453     if (wintype.isEmpty())
02454       wintype = mimetype;
02455     KLFMimeExporter *exporter = KLFMimeExporter::mimeExporterLookup(mimetype);
02456     if (exporter == NULL) {
02457       qWarning()<<KLF_FUNC_NAME<<": Can't find exporter for type "<<mimetype
02458                 <<", winformat="<<wintype<<".";
02459       continue;
02460     }
02461     QByteArray data = exporter->data(mimetype, _output);
02462     wintypes << wintype;
02463     datalist << data;
02464   }
02465 
02466   klfWinClipboardCopy(winId(), wintypes, datalist);
02467 
02468 #else
02469   KLFMimeData *mimedata = new KLFMimeData(klfconfig.UI.copyExportProfile, _output);
02470   QApplication::clipboard()->setMimeData(mimedata, QClipboard::Clipboard);
02471 #endif
02472 
02473   KLFMimeExportProfile profile = KLFMimeExportProfile::findExportProfile(klfconfig.UI.copyExportProfile);
02474   showExportMsgLabel(tr("Copied as <b>%1</b>").arg(profile.description()));
02475 }
02476 
02477 void KLFMainWin::slotSave(const QString& suggestfname)
02478 {
02479   // application-long persistent selectedfilter
02480   static QString selectedfilter;
02481   
02482   QStringList formatlist, filterformatlist;
02483   QMap<QString,QString> formatsByFilterName;
02484   QList<QByteArray> formats = QImageWriter::supportedImageFormats();
02485 
02486   for (QList<QByteArray>::iterator it = formats.begin(); it != formats.end(); ++it) {
02487     QString f = (*it).toLower();
02488     if (f == "jpg" || f == "jpeg" || f == "png" || f == "pdf" || f == "eps")
02489       continue;
02490     QString s = tr("%1 Image (*.%2)").arg(f).arg(f);
02491     filterformatlist << s;
02492     formatlist.push_back(f);
02493     formatsByFilterName[s] = f;
02494   }
02495 
02496   QMap<QString,QString> externFormatsByFilterName;
02497   QMap<QString,KLFAbstractOutputSaver*> externSaverByKey;
02498   int k, j;
02499   for (k = 0; k < pOutputSavers.size(); ++k) {
02500     QStringList xoformats = pOutputSavers[k]->supportedMimeFormats();
02501     for (j = 0; j < xoformats.size(); ++j) {
02502       QString f = QString("%1 (%2)").arg(pOutputSavers[k]->formatTitle(xoformats[j]),
02503                                          pOutputSavers[k]->formatFilePatterns(xoformats[j]).join(" "));
02504       filterformatlist << f;
02505       externFormatsByFilterName[f] = xoformats[j];
02506       externSaverByKey[xoformats[j]] = pOutputSavers[k];
02507     }
02508   }
02509 
02510   QString s;
02511   s = tr("EPS PostScript (*.eps)");
02512   filterformatlist.push_front(s);
02513   formatlist.push_front("eps");
02514   formatsByFilterName[s] = "eps";
02515   s = tr("PDF Portable Document Format (*.pdf)");
02516   filterformatlist.push_front(s);
02517   formatlist.push_front("pdf");
02518   formatsByFilterName[s] = "pdf";
02519   s = tr("Standard JPEG Image (*.jpg *.jpeg)");
02520   filterformatlist.push_front(s);
02521   formatlist.push_front("jpeg");
02522   formatlist.push_front("jpg");
02523   formatsByFilterName[s] = "jpeg";
02524   selectedfilter = s = tr("Standard PNG Image (*.png)");
02525   filterformatlist.push_front(s);
02526   formatlist.push_front("png");
02527   formatsByFilterName[s] = "png";
02528 
02529   QString filterformat = filterformatlist.join(";;");
02530   QString fname, format;
02531 
02532   QString suggestion = suggestfname;
02533   if (suggestion.isEmpty())
02534     suggestion = klfconfig.UI.lastSaveDir;
02535   if (suggestion.isEmpty())
02536     suggestion = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
02537 
02538   fname = QFileDialog::getSaveFileName(this, tr("Save Image Formula"), suggestion, filterformat,
02539                                        &selectedfilter);
02540 
02541   if (fname.isEmpty())
02542     return;
02543 
02544   // first test if it's an extern-format
02545   if ( externFormatsByFilterName.contains(selectedfilter) ) {
02546     // use an external output-saver
02547     QString key = externFormatsByFilterName[selectedfilter];
02548     if ( ! externSaverByKey.contains(key) ) {
02549       qWarning()<<KLF_FUNC_NAME<<": Internal error: externSaverByKey() does not contain key="<<key
02550                 <<": "<<externSaverByKey;
02551       return;
02552     }
02553     KLFAbstractOutputSaver *saver = externSaverByKey[key];
02554     if (saver == NULL) {
02555       qWarning()<<KLF_FUNC_NAME<<": Internal error: saver is NULL!";
02556       return;
02557     }
02558     bool result = saver->saveToFile(key, fname, _output);
02559     if (!result)
02560       qWarning()<<KLF_FUNC_NAME<<": saver failed to save format "<<key<<".";
02561     return;
02562   }
02563 
02564   QFileInfo fi(fname);
02565   klfconfig.UI.lastSaveDir = fi.absolutePath();
02566   if ( fi.suffix().length() == 0 ) {
02567     // get format and suffix from selected filter
02568     if ( ! formatsByFilterName.contains(selectedfilter) && ! externFormatsByFilterName.contains(selectedfilter) ) {
02569       qWarning("%s: ERROR: Unknown format filter selected: `%s'! Assuming PNG!\n", KLF_FUNC_NAME,
02570                qPrintable(selectedfilter));
02571       format = "png";
02572     } else {
02573       format = formatsByFilterName[selectedfilter];
02574     }
02575     fname += "."+format;
02576     // !! : fname has changed, potentially the file could exist, user would not have been warned.
02577     if (QFile::exists(fname)) {
02578       int r = QMessageBox::warning(this, tr("File Exists"),
02579                                    tr("The file <b>%1</b> already exists.\nOverwrite?").arg(fname),
02580                                    QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::No);
02581       if (r == QMessageBox::Yes) {
02582         // will continue in this function.
02583       } else if (r == QMessageBox::No) {
02584         // re-prompt for file name & save (by recursion), and return
02585         slotSave(fname);
02586         return;
02587       } else {
02588         // cancel
02589         return;
02590       }
02591     }
02592   }
02593   fi.setFile(fname);
02594   int index = formatlist.indexOf(fi.suffix().toLower());
02595   if ( index < 0 ) {
02596     // select PNG by default if suffix is not recognized
02597     QMessageBox msgbox(this);
02598     msgbox.setIcon(QMessageBox::Warning);
02599     msgbox.setWindowTitle(tr("Extension not recognized"));
02600     msgbox.setText(tr("Extension <b>%1</b> not recognized.").arg(fi.suffix().toUpper()));
02601     msgbox.setInformativeText(tr("Press \"Change\" to change the file name, or \"Use PNG\" to save as PNG."));
02602     QPushButton *png = new QPushButton(tr("Use PNG"), &msgbox);
02603     msgbox.addButton(png, QMessageBox::AcceptRole);
02604     QPushButton *chg  = new QPushButton(tr("Change ..."), &msgbox);
02605     msgbox.addButton(chg, QMessageBox::ActionRole);
02606     QPushButton *cancel = new QPushButton(tr("Cancel"), &msgbox);
02607     msgbox.addButton(cancel, QMessageBox::RejectRole);
02608     msgbox.setDefaultButton(chg);
02609     msgbox.setEscapeButton(cancel);
02610     msgbox.exec();
02611     if (msgbox.clickedButton() == png) {
02612       format = "png";
02613     } else if (msgbox.clickedButton() == cancel) {
02614       return;
02615     } else {
02616       // re-prompt for file name & save (by recursion), and return
02617       slotSave(fname);
02618       return;
02619     }
02620   } else {
02621     format = formatlist[index];
02622   }
02623 
02624   // The Qt dialog, or us, already asked user to confirm overwriting existing files
02625 
02626   QString error;
02627   bool res = KLFBackend::saveOutputToFile(_output, fname, format, &error);
02628   if ( ! res ) {
02629     QMessageBox::critical(this, tr("Error"), error);
02630   }
02631 }
02632 
02633 
02634 void KLFMainWin::slotActivateEditor()
02635 {
02636   raise();
02637   activateWindow();
02638   u->txtLatex->setFocus();
02639 }
02640 
02641 void KLFMainWin::slotActivateEditorSelectAll()
02642 {
02643   slotActivateEditor();
02644   u->txtLatex->selectAll();
02645 }
02646 
02647 void KLFMainWin::slotShowBigPreview()
02648 {
02649   if ( ! u->btnShowBigPreview->isEnabled() )
02650     return;
02651 
02652   QString text =
02653     tr("<p>%1</p><p align=\"right\" style=\"font-size: %2pt; font-style: italic;\">"
02654        "This preview can be opened with the <strong>F2</strong> key. Hit "
02655        "<strong>Esc</strong> to close.</p>")
02656     .arg(u->lblOutput->bigPreviewText())
02657     .arg(QFontInfo(qApp->font()).pointSize()-1);
02658   QWhatsThis::showText(u->btnEvaluate->pos(), text, u->lblOutput);
02659 }
02660 
02661 
02662 
02663 void KLFMainWin::slotPresetDPISender()
02664 {
02665   QAction *a = qobject_cast<QAction*>(sender());
02666   if (a) {
02667     slotSetDPI(a->data().toInt());
02668   }
02669 }
02670 
02671 
02672 KLFStyle KLFMainWin::currentStyle() const
02673 {
02674   KLFStyle sty;
02675 
02676   sty.name = QString::null;
02677   sty.fg_color = u->colFg->color().rgb();
02678   QColor bgc = u->colBg->color();
02679   sty.bg_color = qRgba(bgc.red(), bgc.green(), bgc.blue(), u->chkBgTransparent->isChecked() ? 0 : 255 );
02680   sty.mathmode = (u->chkMathMode->isChecked() ? u->cbxMathMode->currentText() : "...");
02681   sty.preamble = u->txtPreamble->toPlainText();
02682   sty.dpi = u->spnDPI->value();
02683 
02684   if (u->gbxOverrideMargins->isChecked()) {
02685     sty.overrideBBoxExpand.top = u->spnMarginTop->valueInRefUnit();
02686     sty.overrideBBoxExpand.right = u->spnMarginRight->valueInRefUnit();
02687     sty.overrideBBoxExpand.bottom = u->spnMarginBottom->valueInRefUnit();
02688     sty.overrideBBoxExpand.left = u->spnMarginLeft->valueInRefUnit();
02689   }
02690 
02691   return sty;
02692 }
02693 
02694 QFont KLFMainWin::txtLatexFont() const
02695 {
02696   return u->txtLatex->font();
02697 }
02698 QFont KLFMainWin::txtPreambleFont() const
02699 {
02700   return u->txtPreamble->font();
02701 }
02702 
02703 void KLFMainWin::slotLoadStyleAct()
02704 {
02705   QAction *a = qobject_cast<QAction*>(sender());
02706   if (a) {
02707     slotLoadStyle(a->data().toInt());
02708   }
02709 }
02710 
02711 void KLFMainWin::slotLoadStyle(const KLFStyle& style)
02712 {
02713   QColor cfg, cbg;
02714   cfg.setRgb(style.fg_color);
02715   cbg.setRgb(style.bg_color);
02716   u->colFg->setColor(cfg);
02717   u->colBg->setColor(cbg);
02718   u->chkBgTransparent->setChecked(qAlpha(style.bg_color) == 0);
02719   u->chkMathMode->setChecked(style.mathmode.simplified() != "...");
02720   if (style.mathmode.simplified() != "...")
02721     u->cbxMathMode->setEditText(style.mathmode);
02722   slotSetPreamble(style.preamble); // to preserve text edit undo/redo
02723   u->spnDPI->setValue(style.dpi);
02724 
02725   if (style.overrideBBoxExpand.valid()) {
02726     u->gbxOverrideMargins->setChecked(true);
02727     u->spnMarginTop->setValueInRefUnit(style.overrideBBoxExpand.top);
02728     u->spnMarginRight->setValueInRefUnit(style.overrideBBoxExpand.right);
02729     u->spnMarginBottom->setValueInRefUnit(style.overrideBBoxExpand.bottom);
02730     u->spnMarginLeft->setValueInRefUnit(style.overrideBBoxExpand.left);
02731   } else {
02732     u->gbxOverrideMargins->setChecked(false);
02733   }
02734 }
02735 
02736 void KLFMainWin::slotLoadStyle(int n)
02737 {
02738   if (n < 0 || n >= (int)_styles.size())
02739     return; // let's not try to load an inexistant style...
02740 
02741   slotLoadStyle(_styles[n]);
02742 }
02743 void KLFMainWin::slotSaveStyle()
02744 {
02745   KLFStyle sty;
02746 
02747   QString name = QInputDialog::getText(this, tr("Enter Style Name"),
02748                                        tr("Enter new style name:"));
02749   if (name.isEmpty()) {
02750     return;
02751   }
02752 
02753   // check to see if style exists already
02754   int found_i = -1;
02755   for (int kl = 0; found_i == -1 && kl < _styles.size(); ++kl) {
02756     if (_styles[kl].name.trimmed() == name.trimmed()) {
02757       found_i = kl;
02758       // style exists already
02759       int r = QMessageBox::question(this, tr("Overwrite Style"),
02760                                     tr("Style name already exists. Do you want to overwrite?"),
02761                                     QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel, QMessageBox::No);
02762       switch (r) {
02763       case QMessageBox::No:
02764         slotSaveStyle(); // recurse, ask for new name.
02765         return; // and stop this function execution of course!
02766       case QMessageBox::Yes:
02767         break; // continue normally
02768       default:
02769         return; // forget everything; "Cancel"
02770       }
02771     }
02772   }
02773 
02774   sty = currentStyle();
02775   sty.name = name;
02776 
02777   if (found_i == -1)
02778     _styles.append(sty);
02779   else
02780     _styles[found_i] = sty;
02781 
02782   refreshStylePopupMenus();
02783 
02784   // auto-save our style list
02785   saveStyles();
02786 
02787   emit stylesChanged();
02788 }
02789 
02790 void KLFMainWin::slotStyleManager()
02791 {
02792   mStyleManager->show();
02793 }
02794 
02795 
02796 void KLFMainWin::slotSettings()
02797 {
02798   mSettingsDialog->show();
02799 }
02800 
02801 
02802 void KLFMainWin::closeEvent(QCloseEvent *event)
02803 {
02804   if (_ignore_close_event) {
02805     // simple hide, not close
02806     hide();
02807 
02808     event->ignore();
02809     return;
02810   }
02811 
02812   event->accept();
02813   quit();
02814 }
02815 
02816 
02817 
02818 

Generated by doxygen 1.7.3