Rev 10123 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
For general Scribus (>=1.3.2) copyright and licensing information please refer
to the COPYING file provided with the program. Following this notice may exist
a copyright and/or license notice that predates the release of Scribus 1.3.2
for which a new license (GPL+exception) is in place.
*/
/***************************************************************************
* Copyright (C) 2004 by Craig Bradney *
* cbradney@zip.com.au *
* Copyright (C) 2005 by Petr Vanek *
* petr@yarpen.cz *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "helpbrowser.h"
#include <QAction>
#include <QDir>
#include <QDomDocument>
#include <QFileDialog>
#include <QFileInfo>
#include <QHeaderView>
#include <QInputDialog>
#include <QItemSelectionModel>
#include <QList>
#include <QMessageBox>
#include <QModelIndex>
#include <QModelIndexList>
#include <QPainter>
#include <QPrinter>
#include <QProcess>
#include <QPushButton>
#include <QString>
#include <QStandardItem>
#include <QTextEdit>
#include <QTreeView>
#include <QXmlDefaultHandler>
#include <Q3PaintDeviceMetrics>
#include <Q3SimpleRichText>
#include "prefsmanager.h"
#include "util.h"
#if defined(_WIN32)
#include <windows.h>
#include <shellapi.h>
#endif
/*! \brief XML parsef for documantation history.
This is small helper class which reads saved bookmarks configuration
from ~/.scribus/doc/history.xml file.
The reference to historyBrowser is a reference to the dialog.
\author Petr Vanek <petr@yarpen.cz>
*/
class HistoryParser2 : public QXmlDefaultHandler
{
public:
HelpBrowser *helpBrowser;
bool startDocument()
{
return true;
}
bool startElement(const QString&, const QString&, const QString& qName, const QXmlAttributes& attrs)
{
if (qName == "item")
{
struct histd2 his;
his.title = attrs.value(0);
his.url = attrs.value(1);
helpBrowser->mHistory[helpBrowser->histMenu->addAction(his.title)] = his;
}
return true;
}
bool endElement(const QString&, const QString&, const QString&)
{
return true;
}
};
/*! \brief XML parsef for documantation bookmarks.
This is small helper class which reads saved bookmarks configuration
from ~/.scribus/doc/bookmarks.xml file.
The reference to QListView *view is a reference to the list view with bookmarks
\author Petr Vanek <petr@yarpen.cz>
*/
class BookmarkParser2 : public QXmlDefaultHandler
{
public:
QTreeWidget* view;
QMap<QString, QString>* quickHelpIndex;
QMap<QString, QPair<QString, QString> >* bookmarkIndex;
bool startDocument()
{
return true;
}
bool startElement(const QString&, const QString&, const QString& qName, const QXmlAttributes& attrs)
{
if (qName == "item")
{
if (quickHelpIndex->contains(attrs.value(1)))
{
bookmarkIndex->insert(attrs.value(0), qMakePair(attrs.value(1), attrs.value(2)));
view->addTopLevelItem(new QTreeWidgetItem(view, QStringList() << attrs.value(0)));
}
}
return true;
}
bool endElement(const QString&, const QString&, const QString&)
{
return true;
}
};
HelpBrowser::HelpBrowser(QWidget* parent)
: QMainWindow( parent )
{
setupUi(this);
}
HelpBrowser::HelpBrowser( QWidget* parent, const QString& /*caption*/, const QString& guiLanguage, const QString& jumpToSection, const QString& jumpToFile)
: QMainWindow( parent )
{
setupUi(this);
setupLocalUI();
language = guiLanguage.isEmpty() ? QString("en") : guiLanguage.left(2);
languageChange();
menuModel=NULL;
loadMenu();
readBookmarks();
readHistory();
jumpToHelpSection(jumpToSection, jumpToFile );
}
HelpBrowser::~HelpBrowser()
{
}
void HelpBrowser::closeEvent(QCloseEvent * event)
{
delete menuModel;
// no need to delete child widgets, Qt does it all for us
// bookmarks
QFile bookFile(bookmarkFile());
if (bookFile.open(QIODevice::WriteOnly))
{
QTextStream stream(&bookFile);
stream.setCodec("UTF-8");
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
stream << "<bookmarks>\n";
QTreeWidgetItemIterator it(bookmarksView);
while (*it)
{
if (bookmarkIndex.contains((*it)->text(0)))
{
QString pagetitle(bookmarkIndex.value((*it)->text(0)).first);
QString filename(bookmarkIndex.value((*it)->text(0)).second);
stream << "\t<item title=\"" << (*it)->text(0) << "\" pagetitle=\"" << pagetitle << "\" url=\"" << filename << "\" />\n";
}
++it;
}
stream << "</bookmarks>\n";
bookFile.close();
}
// history
QFile histFile(historyFile());
if (histFile.open(QIODevice::WriteOnly))
{
QTextStream stream(&histFile);
stream.setCodec("UTF-8");
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
stream << "<history>\n";
for (QMap<QAction*,histd2>::Iterator it = mHistory.begin() ; it != mHistory.end(); ++it)
stream << "\t<item title=\"" << it.data().title << "\" url=\"" << it.data().url << "\" />\n";
stream << "</history>\n";
histFile.close();
}
// size
prefs->set("xsize", width());
prefs->set("ysize", height());
emit closed();
}
void HelpBrowser::setupLocalUI()
{
setIcon(loadIcon("AppIcon.png"));
//Add Menus
fileMenu=menuBar()->addMenu(tr("&File"));
editMenu=menuBar()->addMenu(tr("&Edit"));
bookMenu=menuBar()->addMenu(tr("&Bookmarks"));
histMenu=new QMenu(this);
//Add Menu items
filePrint=fileMenu->addAction(loadIcon("16/document-print.png"), tr("&Print..."), this, SLOT(print()), Qt::CTRL+Qt::Key_P);
fileMenu->insertSeparator();
fileExit=fileMenu->addAction(loadIcon("exit.png"), tr("E&xit"), this, SLOT(close()));
editFind=editMenu->addAction(loadIcon("find.png"), tr("&Find..."), this, SLOT(find()), Qt::CTRL+Qt::Key_F);
editFindNext=editMenu->addAction( tr("Find &Next"), this, SLOT(findNext()), Qt::Key_F3);
editFindPrev=editMenu->addAction( tr("Find &Previous"), this, SLOT(findPrevious()), Qt::SHIFT+Qt::Key_F3);
bookAdd=bookMenu->addAction( tr("&Add Bookmark"), this, SLOT(bookmarkButton_clicked()), Qt::CTRL+Qt::Key_D);
bookDel=bookMenu->addAction( tr("&Delete"), this, SLOT(deleteBookmarkButton_clicked()));
bookDelAll=bookMenu->addAction( tr("D&elete All"), this, SLOT(deleteAllBookmarkButton_clicked()));
//Add Toolbar items
goHome=toolBar->addAction(loadIcon("16/go-home.png"), "", textBrowser, SLOT(home()));
goBack=toolBar->addAction(loadIcon("16/go-previous.png"), "", textBrowser, SLOT(backward()));
goFwd=toolBar->addAction(loadIcon("16/go-next.png"), "", textBrowser, SLOT(forward()));
goBack->setMenu(histMenu);
listView->header()->hide();
searchingView->header()->hide();
bookmarksView->header()->hide();
splitter->setResizeMode( tabWidget, QSplitter::KeepSize );
splitter->setResizeMode( textBrowser, QSplitter::Stretch );
// reset previous size
prefs = PrefsManager::instance()->prefsFile->getPluginContext("helpbrowser");
int xsize = prefs->getUInt("xsize", 640);
int ysize = prefs->getUInt("ysize", 480);
resize(QSize(xsize, ysize).expandedTo(minimumSizeHint()) );
//basic ui
connect(histMenu, SIGNAL(triggered(QAction*)), this, SLOT(histChosen(QAction*)));
// searching
connect(searchingEdit, SIGNAL(returnPressed()), this, SLOT(searchingButton_clicked()));
connect(searchingButton, SIGNAL(clicked()), this, SLOT(searchingButton_clicked()));
connect(searchingView, SIGNAL(itemClicked( QTreeWidgetItem *, int)), this, SLOT(itemSearchSelected(QTreeWidgetItem *, int)));
// bookmarks
connect(bookmarkButton, SIGNAL(clicked()), this, SLOT(bookmarkButton_clicked()));
connect(deleteBookmarkButton, SIGNAL(clicked()), this, SLOT(deleteBookmarkButton_clicked()));
connect(deleteAllBookmarkButton, SIGNAL(clicked()), this, SLOT(deleteAllBookmarkButton_clicked()));
connect(bookmarksView, SIGNAL(itemClicked( QTreeWidgetItem *, int)), this, SLOT(itemBookmarkSelected(QTreeWidgetItem *, int)));
// links hoover
connect(textBrowser, SIGNAL(overLink(const QString &)), this, SLOT(showLinkContents(const QString &)));
}
void HelpBrowser::showLinkContents(const QString &link)
{
statusBar()->showMessage(link);
}
void HelpBrowser::languageChange()
{
setCaption( tr( "Scribus Online Help" ) );
noHelpMsg=tr("Sorry, no manual available! Please see: http://docs.scribus.net for updated docs\nand www.scribus.net for downloads.");
// listView->clear();
}
void HelpBrowser::print()
{
QPrinter printer;
printer.setFullPage(true);
if (!printer.setup(this))
return;
textBrowser->print(&printer);
}
void HelpBrowser::searchingButton_clicked()
{
// searchingView->clear();
// root files
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
searchingInDirectory(QDir::convertSeparators(ScPaths::instance().docDir() + language + "/"));
QApplication::restoreOverrideCursor();
}
void HelpBrowser::searchingInDirectory(const QString& aDir)
{
QDir dir(QDir::convertSeparators(aDir + "/"));
QStringList lst = dir.entryList("*.html");
for (QStringList::Iterator it = lst.begin(); it != lst.end(); ++it)
{
QString fname(aDir + (*it));
QFile f(fname);
if (f.open(QIODevice::ReadOnly))
{
QTextStream stream(&f);
QString str = stream.readAll();
int cnt = str.count(searchingEdit->text(), Qt::CaseInsensitive);
if (cnt > 0)
{
QString fullname = fname;
QString toFind(fname.remove(QDir::convertSeparators(ScPaths::instance().docDir()+language + "/")));
QMapIterator<QString, QString> i(quickHelpIndex);
while (i.hasNext())
{
i.next();
if (i.value()==toFind)
searchingView->addTopLevelItem(new QTreeWidgetItem(searchingView, QStringList() << i.key()));
}
}
f.close();
}
}
// get dirs - ugly recursion
QStringList dst = dir.entryList("*", QDir::Dirs);
for (QStringList::Iterator it = dst.begin(); it != dst.end(); ++it)
if ((*it)!="." && (*it)!="..")
searchingInDirectory(QDir::convertSeparators(aDir + QString((*it)) + "/"));
}
void HelpBrowser::find()
{
findText = QInputDialog::getText( tr("Find"), tr("Search Term:"), QLineEdit::Normal, findText, 0, this);
if (findText.isNull())
return;
findNext();
}
void HelpBrowser::findNext()
{
if (findText.isNull())
{
find();
return;
}
// find it. finally
textBrowser->find(findText, 0);
}
void HelpBrowser::findPrevious()
{
if (findText.isNull())
{
find();
return;
}
// find it. finally
textBrowser->find(findText);
}
void HelpBrowser::bookmarkButton_clicked()
{
QString title = textBrowser->documentTitle();
QString fname(QDir::cleanDirPath(textBrowser->source()));
title = QInputDialog::getText( tr("New Bookmark"), tr("New Bookmark's Title:"), QLineEdit::Normal, title, 0, this);
// user cancel
if (title.isNull())
return;
QString toFind(fname.remove(QDir::convertSeparators(ScPaths::instance().docDir()+language + "/")));
QMapIterator<QString, QString> i(quickHelpIndex);
while (i.hasNext())
{
i.next();
if (i.value()==toFind)
{
bookmarkIndex.insert(title, qMakePair(i.key(), i.value()));
bookmarksView->addTopLevelItem(new QTreeWidgetItem(bookmarksView, QStringList() << title));
}
}
}
void HelpBrowser::deleteBookmarkButton_clicked()
{
QTreeWidgetItem *twi=bookmarksView->currentItem();
if (bookmarkIndex.contains(twi->text(0)))
bookmarkIndex.remove(twi->text(0));
delete twi;
}
void HelpBrowser::deleteAllBookmarkButton_clicked()
{
bookmarkIndex.clear();
bookmarksView->clear();
}
void HelpBrowser::histChosen(QAction* i)
{
if (mHistory.contains(i))
textBrowser->setSource( QUrl::fromLocalFile(mHistory[i].url) );
}
void HelpBrowser::jumpToHelpSection(const QString& jumpToSection, const QString& jumpToFile)
{
QString toLoad;
bool noDocs=false;
if (jumpToFile.isEmpty())
{
toLoad = ScPaths::instance().docDir() + language + "/"; //clean this later to handle 5 char locales
if (jumpToSection.isEmpty())
{
QModelIndex index=menuModel->index(0,1);
if (index.isValid())
{
listView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
toLoad += menuModel->data(index, Qt::DisplayRole).toString();
}
else
noDocs=true;
}
else if (jumpToSection=="scripter")
{
// toLoad+="scripter1.html";
// Q3ListViewItemIterator it(listView);
// while (it.current())
// {
// if (it.current()->text(1)=="scripter1.html")
// listView->setSelected( it.current(), true );
// if (it.current()->text(1)=="developers.html")
// it.current()->setOpen( true );
// ++it;
// }
}
}
else
toLoad=jumpToFile;
if (!noDocs)
loadHelp(toLoad);
else
textBrowser->setText("<h2>"+ noHelpMsg +"</h2>");
}
void HelpBrowser::loadHelp(const QString& filename)
{
struct histd2 his;
bool Avail = true;
QString toLoad;
QFileInfo fi;
fi = QFileInfo(filename);
if (fi.fileName().length()>0)
{
if (fi.exists())
toLoad=filename;
else
{
toLoad = QDir::convertSeparators(ScPaths::instance().docDir() + "en/index.html");
language="en";
fi = QFileInfo(toLoad);
if (!fi.exists())
{
textBrowser->setText("<h2>"+ noHelpMsg +"</h2>");
Avail = false;
}
}
}
else
Avail=false;
if (Avail)
{
textBrowser->setSource( QUrl::fromLocalFile(toLoad) );
his.title = textBrowser->documentTitle();
if (his.title.isEmpty())
his.title = toLoad;
his.url = toLoad;
mHistory[histMenu->addAction(his.title)] = his;
}
if (mHistory.count() > 15)
{
QAction* first=histMenu->actions().first();
mHistory.remove(first);
histMenu->removeAction(first);
}
}
void HelpBrowser::loadMenu()
{
QString pfad = ScPaths::instance().docDir();
QString toLoad;
QString pfad2 = QDir::convertSeparators(pfad + language + "/menu.xml");
QFileInfo fi = QFileInfo(pfad2);
if (fi.exists())
toLoad=pfad2;
else
{
toLoad = QDir::convertSeparators(pfad + "en/menu.xml");
language="en";
fi = QFileInfo(toLoad);
sDebug("Scribus help in your selected language does not exist, trying English. Otherwise, please visit http://docs.scribus.net.");
}
if (fi.exists())
{
if (menuModel!=NULL)
delete menuModel;
menuModel=new ScHelpTreeModel(toLoad, "Topic", "Location", &quickHelpIndex);
}
listView->setModel(menuModel);
listView->setSelectionMode(QAbstractItemView::SingleSelection);
QItemSelectionModel *selectionModel = new QItemSelectionModel(menuModel);
listView->setSelectionModel(selectionModel);
connect(listView->selectionModel(), SIGNAL(selectionChanged( const QItemSelection &, const QItemSelection &)), this, SLOT(itemSelected( const QItemSelection &, const QItemSelection &)));
listView->setColumnHidden(1,true);
}
void HelpBrowser::readBookmarks()
{
BookmarkParser2 handler;
handler.view = bookmarksView;
handler.quickHelpIndex=&quickHelpIndex;
handler.bookmarkIndex=&bookmarkIndex;
QFile xmlFile(bookmarkFile());
QXmlInputSource source(xmlFile);
QXmlSimpleReader reader;
reader.setContentHandler(&handler);
reader.parse(source);
}
void HelpBrowser::readHistory()
{
HistoryParser2 handler;
handler.helpBrowser = this;
QFile xmlFile(historyFile());
QXmlInputSource source(xmlFile);
QXmlSimpleReader reader;
reader.setContentHandler(&handler);
reader.parse(source);
}
void HelpBrowser::setText(const QString& str)
{
textBrowser->setText(str);
}
void HelpBrowser::itemSelected(const QItemSelection & selected, const QItemSelection & deselected)
{
Q_UNUSED(deselected);
QModelIndex index;
QModelIndexList items = selected.indexes();
int i=0;
foreach (index, items)
{
if (i==1) // skip 0, as this is always the rootitem, even if we are selecting the rootitem. hmm
{
QString filename(menuModel->data(index, Qt::DisplayRole).toString());
if (!filename.isEmpty())
{
loadHelp(QDir::convertSeparators(ScPaths::instance().docDir() + language + "/" + filename));
}
}
++i;
}
}
void HelpBrowser::itemSearchSelected(QTreeWidgetItem *twi, int i)
{
Q_UNUSED(i);
if (!twi)
return;
if (quickHelpIndex.contains(twi->text(0)))
{
QString filename(quickHelpIndex.value(twi->text(0)));
if (!filename.isEmpty())
{
loadHelp(QDir::convertSeparators(ScPaths::instance().docDir() + language + "/" + filename));
findText = searchingEdit->text();
findNext();
}
}
}
void HelpBrowser::itemBookmarkSelected(QTreeWidgetItem *twi, int i)
{
Q_UNUSED(i);
if (!twi)
return;
if (bookmarkIndex.contains(twi->text(0)))
{
QString filename(bookmarkIndex.value(twi->text(0)).second);
if (!filename.isEmpty())
loadHelp(QDir::convertSeparators(ScPaths::instance().docDir() + language + "/" + filename));
}
}
/*! \brief Returns the name of the cfg file for bookmarks.
A helper function.
\author Petr Vanek <petr@yarpen.cz>
*/
QString HelpBrowser::bookmarkFile()
{
QString appDataDir(ScPaths::getApplicationDataDir());
QString fname(appDataDir + "doc/bookmarks.xml");
if (!QFile::exists(fname))
{
QDir d(QDir::convertSeparators(appDataDir));
d.mkdir("doc");
}
return fname;
}
/*! \brief Returns the name of the cfg file for persistent history.
A helper function.
\author Petr Vanek <petr@yarpen.cz>
*/
QString HelpBrowser::historyFile()
{
QString appDataDir(ScPaths::getApplicationDataDir());
QString fname(appDataDir + "doc/history.xml");
if (!QFile::exists(fname))
{
QDir d(QDir::convertSeparators(appDataDir));
d.mkdir("doc");
}
return fname;
}