summaryrefslogtreecommitdiffstats
path: root/scribus/latexeditor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scribus/latexeditor.cpp')
-rw-r--r--scribus/latexeditor.cpp889
1 files changed, 889 insertions, 0 deletions
diff --git a/scribus/latexeditor.cpp b/scribus/latexeditor.cpp
new file mode 100644
index 0000000..0eb6b21
--- /dev/null
+++ b/scribus/latexeditor.cpp
@@ -0,0 +1,889 @@
+/*
+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.
+*/
+/***************************************************************************
+ latexeditor.cpp - description
+ -------------------
+copyright : Scribus Team
+***************************************************************************/
+
+/***************************************************************************
+* *
+* 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. *
+* *
+***************************************************************************/
+#include "latexeditor.h"
+#include "latexhelpers.h"
+#include "pageitem_latexframe.h"
+#include "prefsmanager.h"
+
+#include <QDebug>
+#include <QFile>
+#include <QFrame>
+#include <QFontComboBox>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QListWidget>
+#include <QMessageBox>
+#include <QTemporaryFile>
+#include <math.h>
+#include "filewatcher.h"
+#include "util.h"
+
+LatexEditor::LatexEditor(PageItem_LatexFrame *frame):QDialog(), frame(frame)
+{
+ setupUi(this);
+
+ //Fill application list
+ programComboBox->clear();
+ QStringList configs = PrefsManager::instance()->latexConfigs();
+ foreach (QString config, configs)
+ {
+ QString name = LatexConfigCache::instance()->parser(config)->description();
+ programComboBox->addItem(name, config);
+ QString iconname = LatexConfigCache::instance()->parser(config)->icon();
+ if (!iconname.isEmpty())
+ {
+ programComboBox->setItemIcon(programComboBox->count()-1, icon(config, iconname));
+ }
+ }
+
+ highlighter = new LatexHighlighter(sourceTextEdit->document());
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(okClicked()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(cancelClicked()));
+ connect(updatePushButton, SIGNAL(clicked(bool)), this, SLOT(updateClicked(bool)));
+ connect(revertPushButton, SIGNAL(clicked(bool)), this, SLOT(revertClicked(bool)));
+ connect(killPushButton, SIGNAL(clicked(bool)), frame, SLOT(killProcess()));
+ connect(externalEditorPushButton, SIGNAL(clicked(bool)), this, SLOT(extEditorClicked()));
+ connect(frame, SIGNAL(formulaAutoUpdate(QString, QString)), this, SLOT(formulaChanged(QString, QString)));
+ connect(frame, SIGNAL(latexFinished()), this, SLOT(latexFinished()));
+ connect(frame, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(stateChanged(QProcess::ProcessState)));
+ connect(programComboBox, SIGNAL(activated(int)), this, SLOT(applicationChanged()));
+ updateConfigFile();
+
+ extEditor = new QProcess();
+ connect(extEditor, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(extEditorFinished(int, QProcess::ExitStatus)));
+ connect(extEditor, SIGNAL(error(QProcess::ProcessError)), this, SLOT(extEditorError(QProcess::ProcessError)));
+ extEditor->setProcessChannelMode(QProcess::MergedChannels);
+
+ fileWatcher = new FileWatcher(this);
+ fileWatcher->stop();
+ fileWatcher->setTimeOut(1500);
+}
+
+LatexEditor::~LatexEditor()
+{
+ //IMPORTANT: Make sure no signals are emitted which
+ // would cause crashes because the handlers access undefined memory.
+ fileWatcher->disconnect();
+ delete fileWatcher;
+
+ extEditor->disconnect();
+ //No need to kill the editor
+ delete extEditor;
+
+ QDir dir;
+ if (!extEditorFile.isEmpty() && !dir.remove(extEditorFile)) {
+ qCritical() << "RENDER FRAME: Failed to remove editorfile" << qPrintable(extEditorFile);
+ }
+
+ buttonBox->disconnect();
+ exitEditor();
+ delete highlighter;
+}
+
+void LatexEditor::changeEvent(QEvent *e)
+{
+ if (e->type() == QEvent::LanguageChange)
+ {
+ retranslateUi(this);
+ loadSettings();
+ }
+ else
+ QWidget::changeEvent(e);
+}
+
+void LatexEditor::startEditor()
+{
+ revert();
+ initialize();
+ show();
+}
+
+void LatexEditor::extEditorClicked()
+{
+ if (extEditor->state() != QProcess::NotRunning) {
+ QMessageBox::information(0, tr("Information"),
+ "<qt>" + tr("An editor for this frame is already running!") +
+ "</qt>", 1, 0, 0);
+ return;
+ }
+
+ QString full_command = PrefsManager::instance()->latexEditorExecutable();
+ if (full_command.isEmpty()) {
+ QMessageBox::information(0, tr("Information"),
+ "<qt>" + tr("Please specify an editor in the preferences!") +
+ "</qt>",1, 0, 0);
+ return;
+ }
+
+ writeExternalEditorFile(); //Don't move this command! It sets extEditorFile
+
+ QString editorFilePath = QString("\"%1\"").arg(extEditorFile);
+ QString tempFilePath = QString("\"%1\"").arg(getLongPathName(QDir::tempPath()));
+ if (full_command.contains("%file")) {
+ full_command.replace("%file", QDir::toNativeSeparators(editorFilePath));
+ } else {
+ full_command += " " + QDir::toNativeSeparators(editorFilePath);
+ }
+ full_command.replace("%dir", QDir::toNativeSeparators(tempFilePath));
+
+ extEditor->setWorkingDirectory(QDir::tempPath());
+
+ externalEditorPushButton->setEnabled(false);
+ externalEditorPushButton->setText(tr("Editor running!"));
+
+ extEditor->start(full_command);
+}
+
+void LatexEditor::writeExternalEditorFile()
+{
+ fileWatcher->stop();
+ fileWatcher->disconnect(); //Avoid triggering false updates
+
+ //First create a temp file name
+ if (extEditorFile.isEmpty()) {
+ QTemporaryFile *editortempfile = new QTemporaryFile(
+ QDir::tempPath() + "/scribus_temp_editor_XXXXXX");
+ if (!editortempfile->open()) {
+ QMessageBox::critical(0, tr("Error"), "<qt>" +
+ tr("Could not create a temporary file to run the external editor!")
+ + "</qt>", 1, 0, 0);
+ }
+ extEditorFile = getLongPathName(editortempfile->fileName());
+ editortempfile->setAutoRemove(false);
+ editortempfile->close();
+ delete editortempfile;
+ fileWatcher->addFile(extEditorFile);
+ }
+ QFile f(extEditorFile);
+ f.open(QIODevice::WriteOnly);
+ f.write(frame->formula().toUtf8());
+ f.close();
+ fileWatcher->forceScan();
+ connect(fileWatcher, SIGNAL(fileChanged(QString)),
+ this, SLOT(extEditorFileChanged(QString)));
+ fileWatcher->start();
+}
+
+void LatexEditor::loadExternalEditorFile()
+{
+ QString new_formula;
+ QFile f(extEditorFile);
+ f.open(QIODevice::ReadOnly);
+ new_formula = QString::fromUtf8(f.readAll());
+ f.close();
+ if (!new_formula.isEmpty()) {
+ frame->setFormula(new_formula);
+ sourceTextEdit->setPlainText(new_formula);
+ }
+ this->update();
+}
+
+void LatexEditor::extEditorFinished(int exitCode, QProcess::ExitStatus exitStatus)
+{
+ externalEditorPushButton->setEnabled(true);
+ externalEditorPushButton->setText( tr("Run External Editor...") );
+ if (exitCode && extEditor) {
+ qCritical() << "RENDER FRAME: Editor failed. Output was: " <<
+ qPrintable(QString(extEditor->readAllStandardOutput()));
+ QMessageBox::critical(0, tr("Error"), "<qt>" +
+ tr("Running the editor failed with exitcode %d!").arg(exitCode) +
+ "</qt>", 1, 0, 0);
+ return;
+ }
+}
+
+void LatexEditor::extEditorFileChanged(QString filename)
+{
+ loadExternalEditorFile();
+ frame->rerunApplication();
+}
+
+void LatexEditor::extEditorError(QProcess::ProcessError error)
+{
+ externalEditorPushButton->setEnabled(true);
+ externalEditorPushButton->setText( tr("Run External Editor...") );
+ QMessageBox::critical(0, tr("Error"), "<qt>" +
+ tr("Running the editor \"%1\" failed!").
+ arg(PrefsManager::instance()->latexEditorExecutable()) +
+ "</qt>", 1, 0, 0);
+}
+
+void LatexEditor::exitEditor()
+{
+ hide();
+}
+
+void LatexEditor::revert()
+{
+ sourceTextEdit->setPlainText(frame->formula());
+}
+
+void LatexEditor::initialize()
+{
+ preambleCheckBox->setChecked(frame->usePreamble());
+ dpiSpinBox->setValue(frame->dpi());
+ stateChanged(frame->state());
+ messagesTextEdit->setPlainText(frame->output());
+ disconnect(programComboBox, SIGNAL(activated(int)), this, SLOT(applicationChanged()));
+ int ind = programComboBox->findData(frame->configFile()); //TODO: Needs special care wrt relative filenames
+ if (ind != -1)
+ programComboBox->setCurrentIndex(ind);
+ connect(programComboBox, SIGNAL(activated(int)), this, SLOT(applicationChanged()));
+}
+
+void LatexEditor::apply(bool force)
+{
+ bool changed = frame->setFormula(sourceTextEdit->toPlainText());
+
+ //TODO: Needs special care wrt relative filenames
+ QString newConfig = programComboBox->itemData(programComboBox->currentIndex()).toString();
+ if (newConfig != frame->configFile()) {
+ changed = true;
+ frame->setConfigFile(newConfig);
+ }
+
+ if (frame->usePreamble() != preambleCheckBox->isChecked() ||
+ frame->dpi() != dpiSpinBox->value()) {
+ changed = true;
+ frame->setUsePreamble(preambleCheckBox->isChecked());
+ frame->setDpi(dpiSpinBox->value());
+ }
+ QString key;
+ QString value;
+
+ QMapIterator<QString, XmlWidget *> i(widgetMap);
+ while (i.hasNext()) {
+ i.next();
+ key = i.key();
+ value = i.value()->toString();
+ if (frame->editorProperties[key] != value) {
+ changed = true;
+ frame->editorProperties[key] = value;
+ }
+ }
+
+ if (changed || force) {
+ frame->rerunApplication(true);
+ }
+}
+
+void LatexEditor::applicationChanged()
+{
+ //TODO: Needs special care wrt relative filenames
+ QString newConfig = programComboBox->itemData(programComboBox->currentIndex()).toString();
+ if (newConfig != frame->configFile())
+ {
+ frame->setConfigFile(newConfig);
+ updateConfigFile();
+ frame->rerunApplication(true);
+ sourceTextEdit->setPlainText(frame->formula());
+ }
+}
+
+void LatexEditor::formulaChanged(QString oldText, QString newText)
+{
+ sourceTextEdit->setPlainText(newText);
+}
+
+void LatexEditor::okClicked()
+{
+ apply();
+ exitEditor();
+}
+
+void LatexEditor::cancelClicked()
+{
+ revert();
+ exitEditor();
+}
+
+void LatexEditor::revertClicked(bool unused)
+{
+ revert();
+}
+
+void LatexEditor::updateClicked(bool unused)
+{
+ apply(true);
+}
+
+void LatexEditor::latexFinished()
+{
+ messagesTextEdit->setPlainText(frame->output());
+}
+
+void LatexEditor::stateChanged(QProcess::ProcessState state)
+{
+ if (state == QProcess::Starting) {
+ messagesTextEdit->setPlainText("");
+ }
+ QString text( tr("Status: ") );
+ if (state == QProcess::NotRunning)
+ {
+ if (frame->error())
+ text += tr("Error");
+ else
+ text += tr("Finished");
+ }
+ else
+ text += tr("Running");
+
+ statusLabel->setText(text);
+ killPushButton->setEnabled(state != QProcess::NotRunning);
+}
+
+
+QIcon LatexEditor::icon(QString config, QString fn)
+{
+ QFileInfo fiConfig(LatexConfigParser::absoluteFilename(config));
+ QFileInfo fiIcon(fiConfig.path()+"/"+fn);
+ if (fiIcon.exists() && fiIcon.isReadable()) {
+ return QIcon(fiConfig.path()+"/"+fn);
+ } else {
+ QIcon *tmp = IconBuffer::instance()->icon(
+ iconFile(config), fn);
+ if (tmp) return *tmp; else return QIcon();
+ }
+}
+
+
+QString LatexEditor::iconFile(QString config)
+{
+ QFileInfo fiConfig(LatexConfigParser::absoluteFilename(config));
+ return fiConfig.path() + "/" + fiConfig.completeBaseName() + ".tar";
+}
+
+
+void LatexEditor::updateConfigFile()
+{
+ QString newConfigFile = LatexConfigParser::absoluteFilename(frame->configFile());
+ if (currentConfigFile == newConfigFile) return;
+ currentConfigFile = newConfigFile;
+ currentIconFile = iconFile(currentConfigFile);
+ QFileInfo fi(currentConfigFile);
+
+ if (!fi.exists() || !fi.isReadable()) {
+ QMessageBox::critical(0, QObject::tr("Error"), "<qt>" +
+ QObject::tr("Configfile %1 not found or the file is not readable").
+ arg(currentConfigFile) + "</qt>", 1, 0, 0);
+ return;
+ }
+
+ loadSettings();
+
+ QMapIterator<QString, XmlWidget *> i(widgetMap);
+ while (i.hasNext()) {
+ i.next();
+ QString key = i.key();
+ XmlWidget *value = i.value();
+ if (frame->editorProperties.contains(key)) {
+ value->fromString(frame->editorProperties[key]);
+ }
+ }
+ //TODO: Needs special care wrt relative filenames
+ highlighter->setConfig(&LatexConfigCache::instance()->parser(currentConfigFile)->highlighterRules);
+}
+
+#define xmlError() qWarning() << "XML-ERROR:" << xml->lineNumber() \
+ << ":" << xml->columnNumber() << ":"
+
+void LatexEditor::loadSettings()
+{
+ while (tabWidget->count()>1) {
+ QWidget *widget = tabWidget->widget(1);
+ tabWidget->removeTab(1);
+ delete widget;
+ }
+ widgetMap.clear();
+
+ QFile f(LatexConfigParser::absoluteFilename(frame->configFile()));
+ f.open(QIODevice::ReadOnly);
+ I18nXmlStreamReader xml(&f);
+ while (!xml.atEnd()) {
+ xml.readNext();
+ if (xml.isWhitespace() || xml.isComment()) continue;
+ if (xml.isStartElement() && xml.name() == "tab") {
+ if (xml.attributes().value("type") == "settings") {
+ createNewSettingsTab(&xml);
+ } else if (xml.attributes().value("type") == "items") {
+ createNewItemsTab(&xml);
+ } else {
+ qWarning() << "XML-ERROR: " << xml.lineNumber() << ":"
+ << xml.columnNumber() << ":" << "Unknow tab type"
+ << xml.attributes().value("type").toString();
+ }
+ }
+ }
+ if (xml.hasError()) {
+ qWarning() << "XML-ERROR: " << xml.lineNumber() << ":"
+ << xml.columnNumber() << ":" << xml.errorString();
+ }
+ f.close();
+}
+
+void LatexEditor::createNewSettingsTab(I18nXmlStreamReader *xml)
+{
+ QStringRef tagname;
+ QFrame *newTab = new QFrame();
+ newTab->setFrameShape(QFrame::NoFrame);
+ QGridLayout *layout = new QGridLayout(newTab);
+ layout->setColumnStretch(1, 10);
+ QString type = xml->attributes().value("type").toString();
+
+ QString title = "No Title";
+
+ while (!xml->atEnd()) {
+ xml->readNext();
+ if (xml->isWhitespace() || xml->isComment()) continue;
+ tagname = xml->name();
+ if (xml->isEndElement() && (tagname == "tab")) {
+ break;
+ }
+ if (!xml->isStartElement()) {
+ xmlError() << "Unexpected element (not a start element)!";
+ continue;
+ }
+
+ if (tagname == "comment") {
+ QLabel *label = new QLabel(xml->readI18nText());
+ int row = layout->rowCount();
+ label->setWordWrap(true);
+ layout->addWidget(label, row, 0, 1, 3);
+ } else if (tagname == "title") {
+ title = xml->readI18nText();
+ } else {
+ XmlWidget *widget = XmlWidget::fromXml(xml);
+ if (dynamic_cast<QWidget *>(widget)) {
+ QLabel *label = new QLabel(widget->description());
+ label->setWordWrap(true);
+ QString name = widget->name();
+
+ int row = layout->rowCount();
+ layout->addWidget(label, row, 0);
+ layout->addWidget(dynamic_cast<QWidget *>(widget), row, 1);
+
+ /* Commented out, because it doesn't make much sense. All
+ the options should be handled in the preamble. Keeping this
+ around as a reference for future widgets.
+ StringPushButton *button = new StringPushButton(
+ tr("Insert"), name);
+ connect(button, SIGNAL(clickedWithData(QString)),
+ this, SLOT(tagButtonClicked(QString)));
+ layout->addWidget(button, row, 2);*/
+
+ if (widgetMap.contains(name)) {
+ xmlError() << "There is already an widget with name" <<
+ name << "!";
+ }
+ widgetMap[name] = widget;
+ } else {
+ xmlError() << "Unexpected tag" << tagname.toString() <<
+ "in settings tab";
+ }
+ }
+ }
+ layout->setRowStretch(layout->rowCount(), 10);
+ tabWidget->addTab(newTab, title);
+}
+
+void LatexEditor::createNewItemsTab(I18nXmlStreamReader *xml)
+{
+ QString title = "No Title!";
+
+
+ QFrame *newTab = new QFrame();
+ newTab->setFrameShape(QFrame::NoFrame);
+ QVBoxLayout *vLayout = new QVBoxLayout(newTab);
+
+ QListWidget *iconList = new QListWidget();
+ iconList->setViewMode(QListView::IconMode);
+ iconList->setGridSize(QSize(55, 55));
+ iconList->setMovement(QListView::Static);
+ iconList->setFlow(QListView::LeftToRight);
+ iconList->setWrapping(true);
+ iconList->setResizeMode(QListView::Adjust);
+
+ connect(iconList, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this, SLOT(newItemSelected(QListWidgetItem *, QListWidgetItem *)));
+ connect(iconList, SIGNAL(itemDoubleClicked (QListWidgetItem *)), this, SLOT(itemDoubleClicked(QListWidgetItem *)));
+
+ QHBoxLayout *hLayout = new QHBoxLayout();
+ QLabel *statusLabel = new QLabel(tr("No item selected!"));
+ DataPushButton *insertPushButton = new DataPushButton( tr("Insert Symbol") , iconList);
+ connect(insertPushButton, SIGNAL(clickedWithData(QObject *)), this, SLOT(insertButtonClicked(QObject *)));
+ hLayout->addWidget(statusLabel, 100);
+ hLayout->addWidget(insertPushButton, 0);
+
+ vLayout->addWidget(iconList, 100);
+ vLayout->addLayout(hLayout, 0);
+
+ QStringRef tagname;
+ while (!xml->atEnd())
+ {
+ xml->readNext();
+ if (xml->isWhitespace() || xml->isComment()) continue;
+ tagname = xml->name();
+ if (xml->isEndElement() && (tagname == "tab"))
+ break;
+ if (!xml->isStartElement())
+ {
+ xmlError() << "Unexpected end element "
+ <<tagname.toString()<<"in item tab";
+ continue;
+ }
+ if (tagname == "title")
+ {
+ title = xml->readI18nText();
+ }
+ else if (tagname == "item")
+ {
+ QString value = xml->attributes().value("value").toString();
+ QString img = xml->attributes().value("image").toString();
+ QString text = xml->readI18nText();
+
+ QString status = value;
+ if (text.isEmpty())
+ text = value;
+ else if (text != value)
+ status = text + "(" + value +")";
+
+ QIcon *icon = 0;
+ if (!img.isEmpty())
+ icon = IconBuffer::instance()->icon(currentIconFile, img);
+ QListWidgetItem *item;
+ if (!icon)
+ item = new QListWidgetItem(text, iconList);
+ else
+ item = new QListWidgetItem(*icon, "", iconList);
+ item->setData(Qt::UserRole, value);
+ item->setData(Qt::UserRole + 1, qVariantFromValue((void *) statusLabel)); //UGLY
+ item->setToolTip(text);
+ item->setStatusTip(status);
+ }
+ else
+ {
+ xmlError() << "Unexpected tag" << tagname.toString() <<
+ "in item tab!";
+ continue;
+ }
+ }
+ tabWidget->addTab(newTab, title);
+}
+
+void LatexEditor::tagButtonClicked(QString tagname)
+{
+ sourceTextEdit->insertPlainText("$scribus_"+tagname+"$");
+}
+
+void LatexEditor::newItemSelected(QListWidgetItem *newItem, QListWidgetItem *)
+{
+ QLabel *label = (QLabel *)(newItem->data(Qt::UserRole + 1).value<void *>());
+ label->setText(newItem->statusTip());
+}
+
+void LatexEditor::itemDoubleClicked(QListWidgetItem *item)
+{
+ sourceTextEdit->insertPlainText(item->data(Qt::UserRole).toString());
+}
+
+void LatexEditor::insertButtonClicked(QObject *widget)
+{
+ QListWidget *list = dynamic_cast<QListWidget*>(widget);
+ Q_ASSERT(list);
+ sourceTextEdit->insertPlainText(
+ list->currentItem()->data(Qt::UserRole).toString());
+}
+
+
+class SCRIBUS_API XmlFontComboBox : public XmlWidget, public QFontComboBox
+{
+ public:
+ XmlFontComboBox(I18nXmlStreamReader *xml) : XmlWidget(xml), QFontComboBox()
+ {
+ fromString(m_defaultValue);
+ }
+
+ QString toString() const {
+ return currentFont().toString();
+ }
+
+ void fromString(QString str) {
+ QFont font;
+ font.fromString(str);
+ this->setCurrentFont(font);
+ }
+};
+
+class SCRIBUS_API XmlSpinBox : public XmlWidget, public QSpinBox
+{
+ public:
+ XmlSpinBox(I18nXmlStreamReader *xml) : XmlWidget(xml, false), QSpinBox() {
+ setRange(
+ xml->attributes().value("min").toString().toInt(),
+ xml->attributes().value("max").toString().toInt()
+ );
+ setSingleStep(xml->attributes().value("step").toString().toInt());
+ setSpecialValueText(xml->attributes().value("special").toString());
+ fromString(m_defaultValue);
+ m_description = xml->readI18nText();
+ }
+
+ QString toString() const {
+ if (value() == minimum() && !specialValueText().isEmpty()) {
+ return specialValueText();
+ } else {
+ return QString::number(value());
+ }
+ }
+
+ void fromString(QString str) {
+ if (str == specialValueText()) {
+ setValue(minimum());
+ } else {
+ setValue(str.toInt());
+ }
+ }
+};
+
+class SCRIBUS_API XmlDoubleSpinBox : public XmlWidget, public QDoubleSpinBox
+{
+ public:
+ XmlDoubleSpinBox(I18nXmlStreamReader *xml) :
+ XmlWidget(xml, false), QDoubleSpinBox() {
+ setRange(
+ xml->attributes().value("min").toString().toDouble(),
+ xml->attributes().value("max").toString().toDouble()
+ );
+ setSingleStep(
+ xml->attributes().value("step").toString().toDouble());
+ setSpecialValueText(xml->attributes().value("special").toString());
+ fromString(m_defaultValue);
+ m_description = xml->readI18nText();
+ }
+
+ QString toString() const {
+ if (value() == minimum() && !specialValueText().isEmpty()) {
+ return specialValueText();
+ } else {
+ return QString::number(value());
+ }
+ }
+
+ void fromString(QString str) {
+ if (str == specialValueText()) {
+ setValue(minimum());
+ } else {
+ setValue(str.toDouble());
+ }
+ }
+};
+
+class SCRIBUS_API XmlLineEdit : public XmlWidget, public QLineEdit
+{
+ public:
+ XmlLineEdit(I18nXmlStreamReader *xml) : XmlWidget(xml), QLineEdit() {
+ fromString(m_defaultValue);
+ }
+
+ QString toString() const {
+ return text();
+ }
+
+ void fromString(QString str) {
+ setText(str);
+ }
+};
+
+class SCRIBUS_API XmlTextEdit : public XmlWidget, public QTextEdit
+{
+ public:
+ XmlTextEdit(I18nXmlStreamReader *xml) : XmlWidget(xml), QTextEdit() {
+ fromString(m_defaultValue);
+ }
+
+ QString toString() const {
+ return toPlainText();
+ }
+
+ void fromString(QString str) {
+ setPlainText(str);
+ }
+};
+
+class SCRIBUS_API XmlColorPicker : public XmlWidget, public QLabel
+{
+ public:
+ XmlColorPicker(I18nXmlStreamReader *xml) : XmlWidget(xml),
+ QLabel("Color pickers are not implemented yet!")
+ {
+ setWordWrap(true);
+ fromString(m_defaultValue);
+ }
+
+ QString toString() const {
+ return "Not implemented!";
+ }
+
+ void fromString(QString str) {
+ qDebug() << "Color pickers are not implemented yet!";
+ }
+};
+
+class SCRIBUS_API XmlComboBox : public XmlWidget, public QComboBox
+{
+ public:
+ XmlComboBox(I18nXmlStreamReader *xml) : XmlWidget(xml, false), QComboBox()
+ {
+ QStringRef tagname;
+ while (!xml->atEnd()) {
+ xml->readNext();
+ if (xml->isWhitespace() || xml->isComment()) continue;
+ tagname = xml->name();
+ if (xml->isEndElement() && (tagname == "list")) {
+ fromString(m_defaultValue);
+ return;
+ }
+ if (xml->isEndElement()) {
+ xmlError() << "Unexpected end element" << tagname.toString();
+ continue;
+ }
+ if (tagname == "title") {
+ m_description = xml->readI18nText();
+ } else if (tagname == "option") {
+ QString value = xml->attributes().value("value").toString();
+ QString text = xml->readI18nText();
+ addItem(text, value);
+ } else {
+ xmlError() << "Unexpected tag" << tagname.toString() <<
+ "in list!";
+ }
+ }
+ }
+
+ QString toString() const {
+ return itemData(currentIndex()).toString();
+ }
+
+ void fromString(QString str) {
+ setCurrentIndex(findData(str));
+ }
+};
+
+XmlWidget* XmlWidget::fromXml(I18nXmlStreamReader *xml)
+{
+ QStringRef tagname = xml->name();
+ if (tagname == "font") {
+ return new XmlFontComboBox(xml);
+ }
+ if (tagname == "spinbox") {
+ if (xml->attributes().value("type") == "double")
+ return new XmlDoubleSpinBox(xml);
+ else
+ return new XmlSpinBox(xml);
+ }
+ if (tagname == "color") {
+ return new XmlColorPicker(xml);
+ }
+ if (tagname == "text") {
+ if (xml->attributes().value("type") == "long")
+ return new XmlTextEdit(xml);
+ else
+ return new XmlLineEdit(xml);
+ }
+ if (tagname == "list") {
+ return new XmlComboBox(xml);
+ }
+ return 0;
+}
+
+XmlWidget::XmlWidget(I18nXmlStreamReader *xml, bool readDescription)
+{
+ m_name = xml->attributes().value("name").toString();
+ m_defaultValue = xml->attributes().value("default").toString();
+ if (readDescription)
+ m_description = xml->readI18nText();
+}
+
+void IconBuffer::loadFile(QString filename)
+{
+ if (loadedFiles.contains(filename)) return;
+ loadedFiles << filename;
+ file = new QFile(filename);
+ file->open(QIODevice::ReadOnly);
+ basePos = 0;
+ while (!file->atEnd()) {
+ QString name = readHeader();
+ if (name.isEmpty()) break;
+ if (!len) continue;
+ icons.insert(filename + ":" + name, readData());
+ }
+ file->close();
+ delete file;
+ file = 0;
+}
+
+QIcon *IconBuffer::icon(QString filename, QString name)
+{
+ loadFile(filename);
+ QString cname = filename + ":" + name;
+ if (icons.contains(cname)) {
+ return &(icons[cname]);
+ } else {
+ qWarning() << "Icon" << cname << "not found!";
+ return 0;
+ }
+}
+
+QString IconBuffer::readHeader()
+{
+ //TODO: Error checking
+ Q_ASSERT(file);
+ char buffer[101];
+ file->seek(basePos);
+ file->read(buffer, 100);
+ buffer[100] = 0;
+ QString name = QString::fromAscii(buffer);
+ file->seek(basePos + 124);
+ file->read(buffer, 12);
+ buffer[12] = 0;
+ bool ok;
+ len = QString::fromAscii(buffer).toInt(&ok, 8);
+ basePos += 512;
+ return name;
+}
+
+QIcon IconBuffer::readData()
+{
+ file->seek(basePos);
+ QByteArray data = file->read(len);
+ QPixmap pixmap;
+ pixmap.loadFromData(data);
+ basePos += static_cast<int>(ceil(len/512.0) * 512);
+ return QIcon(pixmap);
+}
+
+IconBuffer *IconBuffer::_instance = 0;
+IconBuffer *IconBuffer::instance()
+{
+ if (!_instance) {
+ _instance = new IconBuffer();
+ }
+ return _instance;
+}