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

src/klflibbrowser_p.h

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   file klflibbrowser_p.h
00003  *   This file is part of the KLatexFormula Project.
00004  *   Copyright (C) 2010 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: klflibbrowser_p.h 560 2010-11-18 22:43:35Z philippe $ */
00023 
00029 #ifndef KLFLIBBROWSER_P_H
00030 #define KLFLIBBROWSER_P_H
00031 
00032 #include <QWidget>
00033 #include <QStackedWidget>
00034 #include <QTabBar>
00035 #include <QTabWidget>
00036 #include <QEvent>
00037 #include <QDragMoveEvent>
00038 #include <QDialog>
00039 #include <QStackedLayout>
00040 #include <QDir>
00041 #include <QFileDialog>
00042 #include <QFileInfo>
00043 #include <QAction>
00044 #include <QSettings>
00045 #include <QSignalMapper>
00046 #include <QDesktopServices>
00047 #include <QMessageBox>
00048 
00049 #include <ui_klflibexportdialog.h>
00050 
00051 #include <klfsearchbar.h>
00052 #include "klflibview.h"
00053 #include "klfconfig.h"
00054 #include "klflibbrowser.h"
00055 
00057 class KLFLibBrowserViewContainer : public QStackedWidget, public KLFSearchableProxy
00058 {
00059   Q_OBJECT
00060 public:
00061   KLFLibBrowserViewContainer(KLFLibResourceEngine *resource, QTabWidget *parent)
00062     : QStackedWidget(parent), pResource(resource)
00063   {
00064     KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00065 
00066     KLF_DEBUG_WATCH_OBJECT(this) ;
00067 
00068     pResFlags = 0x0;
00069 
00070     pViewTypeActionGroup = new QActionGroup(this);
00071     QSignalMapper *actionSignalMapper = new QSignalMapper(this);
00072 
00073     if (pResource == NULL) {
00074       qWarning()<<"KLFLibBrowserViewContainer: NULL RESOURCE! Expect Imminent Crash!";
00075     }
00076     // find OK view type identifiers
00077     QStringList allViewTypeIdents = KLFLibViewFactory::allSupportedViewTypeIdentifiers();
00078     int k;
00079     for (k = 0; k < allViewTypeIdents.size(); ++k) {
00080       QString vtype = allViewTypeIdents[k];
00081       KLFLibViewFactory *factory =
00082         KLFLibViewFactory::findFactoryFor(vtype);
00083       bool thisViewTypeIdentOk = factory->canCreateLibView(vtype, pResource);
00084       if (thisViewTypeIdentOk)
00085         pOkViewTypeIdents << vtype;
00086       // create an action for this view type
00087       QAction *action = new QAction(pViewTypeActionGroup);
00088       action->setText(factory->viewTypeTitle(vtype));
00089       action->setCheckable(true);
00090       connect(action, SIGNAL(triggered(bool)), actionSignalMapper, SLOT(map()));
00091       actionSignalMapper->setMapping(action, vtype);
00092       action->setEnabled(thisViewTypeIdentOk);
00093       action->setData(vtype);
00094       pViewTypeActions << action;
00095     }
00096     connect(actionSignalMapper, SIGNAL(mapped(const QString&)), this, SLOT(openView(const QString&)));
00097 
00098     connect(this, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentChanged(int)));
00099   }
00100   virtual ~KLFLibBrowserViewContainer()
00101   {
00102     KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00103   }
00104 
00105   QUrl url() const {
00106     KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00107 
00108     KLFAbstractLibView * view = qobject_cast<KLFAbstractLibView*>(currentWidget());
00109     if (view == NULL)
00110       return QUrl();
00111     return view->url();
00112   }
00113 
00114   KLFLibResourceEngine * resourceEngine() { return pResource; }
00115 
00116   KLFAbstractLibView * view() {
00117     KLFAbstractLibView * v = qobject_cast<KLFAbstractLibView*>(currentWidget());
00118     if (v == NULL) { klfDbg("view is NULL ..."); }
00119     return v;
00120   }
00121 
00122   QString currentViewTypeIdentifier() {
00123     return pOpenViewTypeIdents.key(currentIndex());
00124   }
00125 
00126   QString defaultSubResource() { return pResource->defaultSubResource(); }
00127 
00128   QStringList supportedViewTypeIdentifiers() const { return pOkViewTypeIdents; }
00129 
00130   QList<QAction*> viewTypeActions() const { return pViewTypeActions; }
00131 
00132   void setResourceRoleFlags(uint flags) {
00133     pResFlags = flags;
00134   }
00135   uint resourceRoleFlags() const { return pResFlags; }
00136 
00137   QVariantMap saveGuiState() const {
00138     KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00139 
00140     QVariantMap v;
00141     QVariantList vlist; // will hold QVariantMap's of each view's state
00142     QString curViewTypeIdent;
00143     QStringList saved_view_types;
00144     for (QMap<QString,int>::const_iterator cit = pOpenViewTypeIdents.begin();
00145          cit != pOpenViewTypeIdents.end(); ++cit) {
00146       KLFAbstractLibView *view = qobject_cast<KLFAbstractLibView*>(widget(*cit));
00147       QString vti = cit.key(); // view type identifier
00148       if (view == currentWidget()) // this is current view -> save it in more global setting
00149         curViewTypeIdent = vti;
00150       QVariantMap vstate;
00151       vstate["ViewTypeIdentifier"] = vti;
00152       vstate["ViewState"] = QVariant::fromValue<QVariantMap>(view->saveGuiState());
00153       vlist << QVariant::fromValue<QVariantMap>(vstate);
00154       saved_view_types << vti;
00155     }
00156     // add also the states that are in pViewState from a previous loadGuiState() and for
00157     // which no view was opened.
00158     QVariantList lastViewStateList = pViewState.value("StateList").toList();
00159     for (QVariantList::const_iterator cit = lastViewStateList.begin();
00160          cit != lastViewStateList.end(); ++cit) {
00161       const QVariantMap& vmap = (*cit).toMap();
00162       // see if we have this view type already
00163       if (saved_view_types.contains(vmap.value("ViewTypeIdentifier").toString()))
00164         continue;
00165       // otherwise, add this view state map too
00166       vlist << QVariant::fromValue<QVariantMap>(vmap);
00167     }
00168     
00169 
00170     v["StateList"] = QVariant::fromValue<QVariantList>(vlist);
00171     // Remember: this next key is queried also by KLFLibBrowser::openResourceByGuiState()
00172     v["CurrentViewTypeIdentifier"] = QVariant::fromValue<QString>(curViewTypeIdent);
00173     return v;
00174   }
00175   void loadGuiState(const QVariantMap& v)
00176   {
00177     KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00178 
00179     pViewState = v;
00180     klfDbg("loading view state map: "<<v) ;
00181 
00182     const QVariantList vlist = v["StateList"].toList(); // will hold QVariantMap's
00183     const QString curvti = v["CurrentViewTypeIdentifier"].toString();
00184     int k;
00185     for (k = 0; k < vlist.size(); ++k) {
00186       const QVariantMap vstate = vlist[k].toMap();
00187       QString vti = vstate["ViewTypeIdentifier"].toString();
00188       klfDbg("considering to restore view type "<<vti) ;
00189       if (vti != curvti)
00190         continue;
00191       klfDbg("restore view type "<<vti) ;
00192 
00193       // open the current view type identifier. The other view type identifiers will have
00194       // their state restored only if the user requests to display that view type.
00195       bool res = openView(vti);
00196       if (!res) {
00197         qWarning()<<"Can't open view of type "<<vti<<" for resource "<<url()<<"!";
00198         continue;
00199       }
00200       KLFAbstractLibView *view
00201         = qobject_cast<KLFAbstractLibView*>(widget(pOpenViewTypeIdents.value(vti)));
00202       if (view == NULL)
00203         continue;
00204       view->restoreGuiState(vstate["ViewState"].toMap());
00205     }
00206     
00207     // raise current view ...
00208     if (!curvti.isEmpty())
00209       openView(curvti);
00210   }
00211 
00212   QList<QAction*> openSubResourceActions()
00213   {
00214     KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00215 
00216     if ( ! (pResource->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResources) )
00217       return QList<QAction*>();
00218 
00219     QList<QAction*> actions;
00220 
00221     QStringList subreslist = pResource->subResourceList();
00222     QUrl baseurl = pResource->url();
00223     int k;
00224     for (k = 0; k < subreslist.size(); ++k) {
00225       QString t;
00226       if (pResource->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResourceProps)
00227         t = pResource->subResourceProperty(subreslist[k],
00228                                           KLFLibResourceEngine::SubResPropTitle).toString();
00229       else
00230         t = subreslist[k];
00231 
00232       QUrl url = baseurl;
00233       url.addQueryItem("klfDefaultSubResource", subreslist[k]);
00234       QString urlstr = url.toString();
00235 
00236       QAction *a = NULL;
00237       if (pOpenSubResActionCache.contains(urlstr)) {
00238         klfDbg("re-using action for url="<<urlstr<<" from our local action cache") ;
00239         a = pOpenSubResActionCache[urlstr];
00240       } else {
00241         klfDbg("creating action for url="<<urlstr<<", it is not yet in our local action cache...") ;
00242         a = new QAction(t, this);
00243         a->setData(url.toString());
00244         connect(a, SIGNAL(triggered()), this, SLOT(internalRequestOpenSubResourceSender()));
00245         pOpenSubResActionCache[urlstr] = a;
00246         KLF_DEBUG_WATCH_OBJECT(a) ;
00247       }
00248       actions << a;
00249       klfDbg(pResource->url().toString()<<": Added action for sub-resource "<<subreslist[k]<<": url is "
00250              <<a->data().toString()) ;
00251     }
00252 
00253     return actions;
00254   }
00255 
00256 public slots:
00257   bool openView(const QString& viewTypeIdent)
00258   {
00259     KLF_DEBUG_TIME_BLOCK(KLF_FUNC_NAME) ;
00260     klfDbg("view type="<<viewTypeIdent<<"; resource URL="<<pResource->url()) ; 
00261 
00262     // see if we already have this view type open and ready
00263     if (pOpenViewTypeIdents.contains(viewTypeIdent)) {
00264       klfDbg( ": view type "<<viewTypeIdent<<" is already open at index ="
00265               <<pOpenViewTypeIdents[viewTypeIdent] ) ;
00266       setCurrentIndex(pOpenViewTypeIdents[viewTypeIdent]);
00267       return true;
00268     }
00269     // otherwise, instanciate view
00270     KLFLibViewFactory *factory =
00271         KLFLibViewFactory::findFactoryFor(viewTypeIdent);
00272     KLFAbstractLibView *v = factory->createLibView(viewTypeIdent, this, pResource);
00273     if (v == NULL) {
00274       qWarning() << "The factory can't open a view of type "<<viewTypeIdent<<"!";
00275       return false;
00276     }
00277     // some view settings as given by klfconfig
00278     if (viewTypeIdent == "default") { // category tree list
00279       KLFLibDefaultView *defview = qobject_cast<KLFLibDefaultView*>(v);
00280       if (defview == NULL) {
00281         qWarning()<<KLF_FUNC_NAME<<": Created view of type"<<viewTypeIdent<<", that is NOT a KLFLibDefaultView ?!?";
00282       } else {
00283         defview->setGroupSubCategories(klfconfig.LibraryBrowser.groupSubCategories);
00284       }
00285     }
00286 
00287     KLF_DEBUG_WATCH_OBJECT(v) ;
00288 
00289     v->setContextMenuPolicy(Qt::CustomContextMenu);
00290     // get informed about selection changes
00291     connect(v, SIGNAL(entriesSelected(const KLFLibEntryList& )),
00292             this, SLOT(slotEntriesSelected(const KLFLibEntryList& )));
00293     // and of new category suggestions
00294     connect(v, SIGNAL(moreCategorySuggestions(const QStringList&)),
00295             this, SLOT(slotMoreCategorySuggestions(const QStringList&)));
00296     // and of restore actions
00297     connect(v, SIGNAL(requestRestore(const KLFLibEntry&, uint)),
00298             this, SLOT(slotRequestRestore(const KLFLibEntry&, uint)));
00299     connect(v, SIGNAL(requestRestoreStyle(const KLFStyle&)),
00300             this, SLOT(slotRequestRestoreStyle(const KLFStyle&)));
00301     // and of after-change refresh
00302     connect(v, SIGNAL(resourceDataChanged(const QList<KLFLib::entryId>&)),
00303             this, SLOT(slotResourceDataChanged(const QList<KLFLib::entryId>&)));
00304     // and of context menu request
00305     connect(v, SIGNAL(customContextMenuRequested(const QPoint&)),
00306             this, SIGNAL(viewContextMenuRequested(const QPoint&)));
00307     // view progress reporting
00308     connect(v, SIGNAL(operationStartReportingProgress(KLFProgressReporter *, const QString&)),
00309             this, SIGNAL(viewOperationStartReportingProgress(KLFProgressReporter *, const QString&)));
00310 
00311     klfDbgT(": connected signals.");
00312     if ((pResource->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResources) &&
00313         (pResource->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResourceProps))
00314       pResource->setSubResourceProperty(pResource->defaultSubResource(),
00315                                         KLFLibResourceEngine::SubResPropViewType, viewTypeIdent);
00316     else
00317       pResource->setViewType(viewTypeIdent);
00318     klfDbgT(": set view type.");
00319 
00320     int curindex = currentIndex();
00321     blockSignals(true);
00322     int index = addWidget(v);
00323     blockSignals(false);
00324     pOpenViewTypeIdents[viewTypeIdent] = index;
00325     klfDbgT(": added widget, about to raise");
00326     if (currentIndex() == curindex)
00327       setCurrentIndex(index); // show new open view (and call slot slotCurrentIndex())
00328     else {
00329       // call now the slot that would have been called with addWidget()
00330       // if the signals hadn't been blocked
00331       slotCurrentChanged(index);
00332     }
00333     klfDbgT(": Added view.");
00334 
00335     // see if we have a GUI state to restore
00336     if (pViewState.contains("StateList")) {
00337       const QVariantList& vlist = pViewState["StateList"].toList(); // will hold QVariantMap's
00338       klfDbg("possibly restoring a GUI state... list size="<<vlist.size()) ;
00339       int k;
00340       for (k = 0; k < vlist.size(); ++k) {
00341         const QVariantMap& vstate = vlist[k].toMap();
00342         QString vti = vstate["ViewTypeIdentifier"].toString();
00343         if (vti != viewTypeIdent)
00344           continue;
00345         klfDbg("Restoring gui state, match found for vti[="<<vti<<"]==viewTypeIdent[="<<viewTypeIdent<<"]!") ;
00346         v->restoreGuiState(vstate["ViewState"].toMap());
00347         break;
00348       }
00349     }
00350     return true;
00351   }
00352 
00353 
00354 signals:
00355   void viewContextMenuRequested(const QPoint& pos);
00356 
00357   void viewTypeChanged(const QString&);
00358 
00359   void requestRestore(const KLFLibEntry& entry, uint restoreflags = KLFLib::RestoreLatexAndStyle);
00360   void requestRestoreStyle(const KLFStyle& style);
00361 
00362   void resourceDataChanged(const QList<KLFLib::entryId>& entryIdList);
00363 
00364   void entriesSelected(const KLFLibEntryList& entries);
00365   void moreCategorySuggestions(const QStringList& categorylist);
00366 
00367   void requestOpenUrl(const QString& url);
00368 
00369   void viewOperationStartReportingProgress(KLFProgressReporter *progressReporter, const QString& descriptiveText);
00370 
00371 protected slots:
00372   void slotRequestRestore(const KLFLibEntry& entry, uint restoreflags = KLFLib::RestoreLatexAndStyle) {
00373     if (sender() == view())
00374       emit requestRestore(entry, restoreflags);
00375   }
00376   void slotRequestRestoreStyle(const KLFStyle& style) {
00377     if (sender() == view())
00378       emit requestRestoreStyle(style);
00379   }
00380   void slotResourceDataChanged(const QList<KLFLib::entryId>& entryIdList) {
00381     if (sender() == view())
00382       emit resourceDataChanged(entryIdList);
00383   }
00384   void slotEntriesSelected(const KLFLibEntryList& entries) {
00385     if (sender() == view())
00386       emit entriesSelected(entries);
00387   }
00388   void slotMoreCategorySuggestions(const QStringList& categorylist) {
00389     if (sender() == view())
00390       emit moreCategorySuggestions(categorylist);
00391   }
00392 
00393   void slotCurrentChanged(int index) {
00394     KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00395 
00396     KLFAbstractLibView *v = view();
00397     if (v == NULL) {
00398       setSearchTarget(NULL);
00399       return;
00400     }
00401     setSearchTarget(v->searchable());
00402     QString vtype = pOpenViewTypeIdents.key(index);
00403     int ai = findViewTypeAction(vtype);
00404     if (ai >= 0)
00405       pViewTypeActions[ai]->setChecked(true);
00406 
00407 
00408     emit viewTypeChanged(vtype);
00409     emit entriesSelected(v->selectedEntries());
00410   }
00411 
00412   void internalRequestOpenSubResourceSender()
00413   {
00414     KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00415 
00416     QAction * a = qobject_cast<QAction*>(sender());
00417     KLF_ASSERT_NOT_NULL( a, "Sender action is NULL", return ) ;
00418 
00419     emit requestOpenUrl(a->data().toString());
00420   }
00421 
00422 protected:
00423   QStringList pOkViewTypeIdents;
00424   KLFLibResourceEngine *pResource;
00425 
00426   QVariantMap pViewState;
00427 
00428 
00430   QMap<QString,int> pOpenViewTypeIdents;
00431   QActionGroup *pViewTypeActionGroup;
00432   QList<QAction*> pViewTypeActions;
00433 
00434   uint pResFlags;
00435 
00436   int findViewTypeAction(const QString& vtype) {
00437     KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00438 
00439     int k;
00440     for (k = 0; k < pViewTypeActions.size(); ++k)
00441       if (pViewTypeActions[k]->data().toString() == vtype)
00442         return k;
00443     return -1;
00444   }
00445 
00446   // re-use "open sub-resource ->" actions within multiple menu appearances
00447   QMap<QString,QAction*> pOpenSubResActionCache;
00448 };
00449 
00450 
00451 // ------------------------
00452 
00453 
00455 class KLFLibBrowserTabWidget : public QTabWidget
00456 {
00457   Q_OBJECT
00458 public:
00459   KLFLibBrowserTabWidget(QWidget *parent) : QTabWidget(parent)
00460   {
00461     setUsesScrollButtons(false);
00462     pTabBar = new QTabBar(this);
00463     pTabBar->setAcceptDrops(true);
00464     pTabBar->installEventFilter(this);
00465     setTabBar(pTabBar);
00466   }
00467   virtual ~KLFLibBrowserTabWidget() { }
00468 
00470   int getTabAtPoint(const QPoint& pos) {
00471     QPoint tabbarpos = pTabBar->mapFromGlobal(mapToGlobal(pos));
00472     return pTabBar->tabAt(tabbarpos);
00473   }
00474 
00476   QRect getTabRect(int tab) {
00477     QRect tabbarrect = pTabBar->tabRect(tab);
00478     return QRect(mapFromGlobal(pTabBar->mapToGlobal(tabbarrect.topLeft())),
00479                  tabbarrect.size());
00480   }
00481 
00482   bool eventFilter(QObject *object, QEvent *event)
00483   {
00484     if (object == pTabBar && event->type() == QEvent::DragEnter) {
00485       QDragEnterEvent *de = (QDragEnterEvent*)event;
00486       de->accept();
00487       return true;
00488     }
00489     if (object == pTabBar && event->type() == QEvent::DragMove) {
00490       // ignore event, but raise the underlying tab.
00491       QDragMoveEvent *de = (QDragMoveEvent*)event;
00492       QPoint pos = de->pos();
00493       de->ignore();
00494       int index = getTabAtPoint(pos);
00495       if (index >= 0)
00496         setCurrentIndex(index);
00497       return true;
00498     }
00499     return QTabWidget::eventFilter(object, event);
00500   }
00501 
00502 
00503   void setTabEnabled(int index, bool enable)
00504   {
00505     QTabWidget::setTabEnabled(index, enable);
00506     emit pageEnabled(index, enable);
00507   }
00508 
00509   void setTabIcon(int index, const QIcon& icon)
00510   {
00511     QTabWidget::setTabIcon(index, icon);
00512     emit pageIconChanged(index, icon);
00513   }
00514 
00515   void setTabText(int index, const QString& label)
00516   {
00517     QTabWidget::setTabText(index, label);
00518     emit pageTextChanged(index, label);
00519   }
00520 
00521 signals:
00522 
00523   void pageInserted(int index, const QIcon& icon, const QString& text);
00524   void pageTextChanged(int index, const QString& text);
00525   void pageIconChanged(int index, const QIcon& icon);
00526   void pageEnabled(int index, bool enable);
00527   void pageRemoved(int index);
00528 
00529 
00530 public slots:
00531 
00532   void refreshTabReadOnly(int tabindex, bool readonly) {
00533     QPalette pal = palette();
00534     
00535     QColor normalColor = pal.color(QPalette::Active, QPalette::ButtonText);
00536     QColor readOnlyColor = pal.color(QPalette::Disabled, QPalette::ButtonText);
00537 
00538     if (readonly)
00539       pTabBar->setTabTextColor(tabindex, readOnlyColor);
00540     else
00541       pTabBar->setTabTextColor(tabindex, normalColor);
00542   }
00543 
00544 protected:
00545 
00546   virtual void tabInserted(int index) {
00547     emit pageInserted(index, tabIcon(index), tabText(index));
00548   }
00549   virtual void tabRemoved(int index) {
00550     emit pageRemoved(index);
00551   }
00552 
00553 private:
00554   QTabBar *pTabBar;
00555 };
00556 
00557 // -----------------------------------------------------------------
00558 
00559 
00560 
00561 class KLFLibBrowserTabMenu : public QMenu
00562 {
00563   Q_OBJECT
00564 public:
00565   KLFLibBrowserTabMenu(KLFLibBrowserTabWidget *tabwidget)
00566     : QMenu(tabwidget), pTabWidget(tabwidget)
00567   {
00568     setTitle(tr("Switch to Tab"));
00569     pActionGroup = new QActionGroup(this);
00570     pActionGroup->setExclusive(true);
00571 
00572     int k;
00573     for (k = 0; k < pTabWidget->count(); ++k) {
00574       slotPageInserted(k, pTabWidget->tabIcon(k), pTabWidget->tabText(k));
00575     }
00576 
00577     connect(pTabWidget, SIGNAL(pageInserted(int, const QIcon&, const QString&)),
00578             this, SLOT(slotPageInserted(int, const QIcon&, const QString&)));
00579     connect(pTabWidget, SIGNAL(pageRemoved(int)), this, SLOT(slotPageRemoved(int)));
00580     connect(pTabWidget, SIGNAL(pageTextChanged(int, const QString&)),
00581             this, SLOT(slotPageTextChanged(int, const QString&)));
00582     connect(pTabWidget, SIGNAL(pageIconChanged(int, const QIcon&)),
00583             this, SLOT(slotPageIconChanged(int, const QIcon&)));
00584     connect(pTabWidget, SIGNAL(pageEnabled(int, bool)), this, SLOT(slotPageEnabled(int, bool)));
00585     connect(pTabWidget, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentIndexChanged(int)));
00586   }
00587   virtual ~KLFLibBrowserTabMenu()
00588   {
00589   }
00590 
00591 protected slots:
00592   void slotPageInserted(int index, const QIcon& icon, const QString& text)
00593   {
00594     KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00595     QAction *a = new QAction(pActionGroup);
00596     a->setIcon(icon);
00597     a->setText(text);
00598     a->setCheckable(true);
00599     connect(a, SIGNAL(triggered()), this, SLOT(slotRaisePageFromAction()));
00600     if (index < actions().size())
00601       insertAction(actions()[index], a);
00602     else
00603       addAction(a);
00604   }
00605   void slotPageRemoved(int index)
00606   {
00607     KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
00608     if (index >= 0 && index < actions().size())
00609       removeAction(actions()[index]);
00610   }
00611   void slotPageTextChanged(int index, const QString& text)
00612   {
00613     if (index >= 0 && index < actions().size())
00614       actions()[index]->setText(text);
00615   }
00616   void slotPageIconChanged(int index, const QIcon& icon)
00617   {
00618     if (index >= 0 && index < actions().size())
00619       actions()[index]->setIcon(icon);
00620   }
00621   void slotPageEnabled(int index, bool enable)
00622   {
00623     if (index >= 0 && index < actions().size())
00624       actions()[index]->setEnabled(enable);
00625   }
00626   void slotCurrentIndexChanged(int index)
00627   {
00628     if (index >= 0 && index < actions().size())
00629       actions()[index]->setChecked(true); // will auto-exclude the others because of exclusive action group
00630   }
00631 
00632 
00633   void slotRaisePageFromAction()
00634   {
00635     QAction * a = qobject_cast<QAction*>(sender());
00636     if (a == NULL) {
00637       qWarning()<<KLF_FUNC_NAME<<": action sender is NULL?!?";
00638       return;
00639     }
00640     int k;
00641     QList<QAction*> alist = actions();
00642     for (k = 0; k < alist.size(); ++k) {
00643       if (alist[k] == a) {
00644         pTabWidget->setCurrentIndex(k);
00645         return;
00646       }
00647     }
00648   }
00649 
00650 private:
00651   QActionGroup *pActionGroup;
00652   KLFLibBrowserTabWidget *pTabWidget;
00653 };
00654 
00655 
00656 
00657 
00658 
00659 
00660 // -----------------------------------------------------------------
00661 
00662 
00664 class KLFLibExportDialog : public QDialog, public Ui::KLFLibExportDialog
00665 {
00666   Q_OBJECT
00667 public:
00668   enum { DataRole = Qt::UserRole, OldCheckStateRole } ;
00669 
00670   static KLFLibResourceEngine * showExportDialogCreateResource(KLFLibBrowser *libbrowser, QList<QUrl> *exportUrls)
00671   {
00672     KLFLibExportDialog dlg(libbrowser);
00673     bool ok;
00674     KLFLibWidgetFactory::Parameters param;
00675     *exportUrls = QList<QUrl>();
00676     do {
00677       int result = dlg.exec();
00678       if (result != QDialog::Accepted)
00679         return NULL; // cancelled by user
00680       param = dlg.wfactory->retrieveCreateParametersFromWidget("LocalFile", dlg.localFileWidget);
00681       ok = true; // by default we got parameters OK
00682       if (param.isEmpty())
00683         ok = false;
00684       if (param.contains("klfRetry") && param["klfRetry"].toBool())
00685         ok = false;
00686       if (param.contains("klfCancel") && param["klfCancel"].toBool())
00687         return NULL; // cancelled
00688     } while (!ok) ;
00689 
00690     QList<QUrl> urls = dlg.selectedExportUrls();
00691     if (urls.isEmpty()) {
00692       QMessageBox::critical(&dlg, tr("Error"), tr("You have not selected any resources to export!"));
00693       return NULL;
00694     }
00695 
00696     // now create the resource
00697     if (!param.contains("klfScheme")) {
00698       qWarning()<<KLF_FUNC_NAME<<": factory create parameters did not provide a scheme!";
00699       return NULL;
00700     }
00701     QString scheme = param["klfScheme"].toString();
00702     KLFLibEngineFactory *efactory = KLFLibEngineFactory::findFactoryFor(scheme);
00703     if (efactory == NULL) {
00704       qWarning()<<KLF_FUNC_NAME<<": can't find factory for scheme "<<scheme<<"!";
00705       return NULL;
00706     }
00707     // this is the sub-resource that will be created with the resource. It will be deleted after
00708     // we filled up the resource. Remember the name ("export_xtra"), it will be deleted at the
00709     // end of KLFLibBrowser::slotExport(), ie. don't change this without consideration.
00710     param["klfDefaultSubResource"] = QLatin1String("export_xtra");
00711 
00712     KLFLibResourceEngine *resource = efactory->createResource(scheme, param, libbrowser);
00713     if (resource == NULL) {
00714       QMessageBox::critical(&dlg, tr("Error"),
00715                             tr("Can't create resource %1!").arg(param["Filename"].toString()));
00716       qWarning()<<KLF_FUNC_NAME<<": Failed to create resource of type "<<scheme<<" with parameters: "<<param;
00717       return NULL;
00718     }
00719     *exportUrls = urls;
00720     return resource;
00721   }
00722 
00723 
00724   KLFLibExportDialog(KLFLibBrowser *libbrowser)
00725     : QDialog(libbrowser, 0), pLibBrowser(libbrowser), pModel(NULL),
00726     pInSlotItemChanged(false)
00727   {
00728     setupUi(this);
00729     setWindowModality(Qt::WindowModal);
00730     setModal(true);
00731 
00732     wfactory = KLFLibWidgetFactory::findFactoryFor("LocalFile");
00733     if (wfactory == NULL) {
00734       qWarning()<<KLF_FUNC_NAME<<": Can't find factory for type 'LocalFile'!";
00735       return;
00736     }
00737     QString mydir = klfconfig.LibraryBrowser.lastFileDialogPath;
00738     KLFLibWidgetFactory::Parameters pdefault;
00739     QString filedate = QDate::currentDate().toString("yyyy-MM-dd");
00740     pdefault["Url"] = QUrl("klf+legacy://"+tr("%1/klatexformula_export_%2.klf").arg(mydir, filedate));
00741     QStackedLayout *lyt_gbxExportLocalFileWidget = new QStackedLayout(gbxExportLocalFileWidget);
00742     lyt_gbxExportLocalFileWidget->setObjectName("lyt_gbxExportLocalFileWidget");
00743     lyt_gbxExportLocalFileWidget->setContentsMargins(0,0,0,0);
00744     lyt_gbxExportLocalFileWidget->setSpacing(0);
00745     localFileWidget = 
00746       wfactory->createPromptCreateParametersWidget(gbxExportLocalFileWidget, "LocalFile", pdefault);
00747     lyt_gbxExportLocalFileWidget->addWidget(localFileWidget);
00748     localFileWidget->setFixedHeight(localFileWidget->minimumSizeHint().height()+4);
00749     gbxExportLocalFileWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
00750 
00751     pModel = new QStandardItemModel(this);
00752     lstRes->setModel(pModel);
00753 
00754     connect(pModel, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(slotItemChanged(QStandardItem*)));
00755 
00756     connect(btnSelectAll, SIGNAL(clicked()), this, SLOT(selectAll()));
00757     connect(btnUnselectAll, SIGNAL(clicked()), this, SLOT(unselectAll()));
00758 
00759     populateExportList();
00760   }
00761 
00762 
00763   QList<QUrl> selectedExportUrls()
00764   {
00765     QList<QUrl> urlList;
00766     int k, j;
00767     QStandardItem *root = pModel->invisibleRootItem();
00768     for (k = 0; k < root->rowCount(); ++k) {
00769       QStandardItem *resItem = root->child(k);
00770       if (resItem->rowCount() > 0) {
00771         // has specific sub-resources
00772         for (j = 0; j < resItem->rowCount(); ++j) {
00773           if (resItem->child(j)->checkState() != Qt::Unchecked) {
00774             QUrl url = resItem->data(DataRole).toString();
00775             url.addQueryItem("klfDefaultSubResource", resItem->child(j)->data(DataRole).toString());
00776             urlList << url;
00777             continue;
00778           }
00779         }
00780       } else {
00781         // no specific sub-resources, ie. the resource does not support sub-resources
00782         if (resItem->checkState() != Qt::Unchecked)
00783           urlList << QUrl(resItem->data(DataRole).toString());
00784       }
00785     }
00786     return urlList;
00787   }
00788 
00789 
00790 public slots:
00791 
00792   void selectAll(bool select = true)
00793   {
00794     // select all root items, their children will follow by cascade
00795     QStandardItem *root = pModel->invisibleRootItem();
00796     int k;
00797     for (k = 0; k < root->rowCount(); ++k) {
00798       root->child(k)->setCheckState(select ? Qt::Checked : Qt::Unchecked);
00799     }
00800   }
00801   void unselectAll()
00802   {
00803     selectAll(false);
00804   }
00805 
00806 private slots:
00807 
00808   void slotItemChanged(QStandardItem *item)
00809   {
00810     if (pInSlotItemChanged)
00811       return;
00812     pInSlotItemChanged = true;
00813     Qt::CheckState chk = item->checkState();
00814     Qt::CheckState oldchk = (Qt::CheckState)item->data(OldCheckStateRole).toInt();
00815     //    printf("Item %p maybe check state changed from %d to %d?\n", (void*)item,
00816     //     oldchk, chk);
00817     if ((chk == Qt::Checked || chk == Qt::Unchecked) && oldchk != chk) {
00818       //      printf("Item %p check state changed from %d to %d!\n", (void*)item, oldchk, chk);
00819       // item was checked or un-checked
00820       item->setData(chk, OldCheckStateRole);
00821       // iterate its children and (un-)check them all
00822       int k;
00823       for (k = 0; k < item->rowCount(); ++k) {
00824         //      printf("-->\n");
00825         item->child(k)->setData(chk, OldCheckStateRole); // no update please
00826         item->child(k)->setCheckState(chk);
00827         //      printf("<--\n");
00828       }
00829       // and now set the parent's item check state to partially checked.
00830       QStandardItem *p = item->parent();
00831       if (p != NULL) {
00832         //      printf("parent-->\n");
00833         p->setData(Qt::PartiallyChecked, OldCheckStateRole);
00834         p->setCheckState(Qt::PartiallyChecked);
00835         //      printf("<--parent\n");
00836       }
00837       //      printf("Done processing item %p check state change from %d to %d\n", (void*)item, oldchk, chk);
00838     }
00839     pInSlotItemChanged = false;
00840   }
00841 
00842 
00843 private:
00844   KLFLibBrowser *pLibBrowser;
00845   QStandardItemModel *pModel;
00846   bool pInSlotItemChanged;
00847 
00848   KLFLibWidgetFactory * wfactory;
00849   QWidget *localFileWidget;
00850 
00851 
00852   void populateExportList()
00853   {
00854     pModel->clear();
00855     pModel->setColumnCount(1);
00856     pModel->setHorizontalHeaderLabels(QStringList()<<tr("Resource", "[[export list title]]"));
00857     
00858     QList<QUrl> openurls = pLibBrowser->openUrls();
00859     int k, j;
00860     for (k = 0; k < openurls.size(); ++k) {
00861       KLFLibResourceEngine *res = pLibBrowser->getOpenResource(openurls[k]);
00862       QStandardItem *parent = getResourceParentItem(res);
00863       QStringList subreslist;
00864       if (openurls[k].hasQueryItem("klfDefaultSubResource")) {
00865         subreslist = QStringList() << openurls[k].queryItemValue("klfDefaultSubResource");
00866       } else if (res->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResources) {
00867         // no default sub-resource is specified, so add them all
00868         subreslist = res->subResourceList();
00869       }
00870       // add all subresources
00871       for (j = 0; j < subreslist.size(); ++j) {
00872         if (findSubResourceItem(res, subreslist[j]) != NULL)
00873           continue;
00874         // create this item
00875         QStandardItem *item = new QStandardItem;
00876         item->setData(subreslist[j], DataRole);
00877         QString srtitle;
00878         if (res->supportedFeatureFlags() & KLFLibResourceEngine::FeatureSubResourceProps)
00879           srtitle =
00880             res->subResourceProperty(subreslist[j], KLFLibResourceEngine::SubResPropTitle).toString();
00881         if (srtitle.isEmpty())
00882           srtitle = subreslist[j];
00883         item->setText(srtitle);
00884         item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
00885         item->setCheckState(Qt::Checked);
00886         item->setData(item->checkState(), OldCheckStateRole);
00887         parent->appendRow(item);
00888         lstRes->setExpanded(pModel->indexFromItem(parent), true);
00889       }
00890     }
00891   }
00892 
00893   QStandardItem *getResourceParentItem(KLFLibResourceEngine *res)
00894   {
00895     QStandardItem *root = pModel->invisibleRootItem();
00896     int j;
00897     for (j = 0; j < root->rowCount(); ++j) {
00898       if (root->child(j)->data(DataRole).value<QString>() == res->url().toString())
00899         return root->child(j);
00900     }
00901     // not existent, need to create it
00902     QStandardItem *item = new QStandardItem;
00903     item->setData(QVariant::fromValue<QString>(res->url().toString()), DataRole);
00904     item->setText(res->title());
00905     item->setFlags(Qt::ItemIsSelectable|Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);
00906     item->setCheckState(Qt::Checked);
00907     item->setData(item->checkState(), OldCheckStateRole);
00908     root->appendRow(item);
00909     return item;
00910   }
00911 
00912   QStandardItem *findSubResourceItem(KLFLibResourceEngine *res, const QString& subResource)
00913   {
00914     QStandardItem *parent = getResourceParentItem(res);
00915     int k;
00916     for (k = 0; k < parent->rowCount(); ++k) {
00917       if (parent->child(k)->data(DataRole) == subResource)
00918         return parent->child(k);
00919     }
00920     return NULL;
00921   }
00922 };
00923 
00924 
00925 
00926 
00927 
00928 /* THIS HAS NEVER BEEN USED NOR TESTED, HOWEVER IT MAY COME IN HANDY IF NEEDED.
00929 
00930 / ** \internal * /
00931 class KLFSignalUnmapper : public QObject
00932 {
00933   Q_OBJECT
00934 public:
00935   KLFSignalUnmapper(QObject *parent) : QObject(parent)
00936   {
00937   }
00938   virtual ~KLFSignalUnmapper() { }
00939 
00940   void registerObject(const QString& key, QObject *object, const QByteArray& member,
00941                       QList<QGenericArgument> staticArgs)
00942   {
00943     UnmappedObject o;
00944     o.key = key;
00945     o.object = object;
00946     o.member = member;
00947     o.staticArgs = staticArgs;
00948     unmappedObjects << o;
00949     connect(o.object, SIGNAL(destroyed()), this, SLOT(unregisterObjectSender()));
00950   }
00951 
00952 public slots:
00953   void unmap(const QString& key) {
00954     int k;
00955     for (k = 0; k < unmappedObjects.size(); ++k) {
00956       if (unmappedObjects[k].key == key) {
00957         const QList<QGenericArgument>& al = unmappedObjects[k].staticArgs;
00958         QMetaObject::invokeMethod(unmappedObjects[k].object, unmappedObjects[k].member,
00959                                   al.value(0), al.value(1), al.value(2), al.value(3), al.value(4),
00960                                   al.value(5), al.value(6), al.value(7), al.value(8), al.value(9));
00961       }
00962     }
00963   }
00964 
00965   void unregisterObject(QObject *object) {
00966     int k;
00967     for (k = 0; k < unmappedObjects.size(); ++k)
00968       if (unmappedObjects[k].object == object)
00969         unmappedObjects.removeAt(k);
00970   }
00971 
00972 private slots:
00973   void unregisterObjectSender() {
00974     QObject *object = sender();
00975     if (object == NULL)
00976       return;
00977     unregisterObject(object);
00978   }
00979 
00980 private:
00981   struct UnmappedObject {
00982     QString key;
00983     QObject *object;
00984     QByteArray member;
00985     QList<QGenericArgument> staticArgs;
00986   };
00987   QList<UnmappedObject> unmappedObjects;
00988 };
00989 */
00990 
00991 
00992 
00993 #endif

Generated by doxygen 1.7.3