/***************************************************************************
* file klfmainwin_p.h
* This file is part of the KLatexFormula Project.
* Copyright (C) 2011 by Philippe Faist
* philippe.faist at bluewin.ch
* *
* 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. *
***************************************************************************/
/* $Id$ */
#ifndef KLFMAINWIN_P_H
#define KLFMAINWIN_P_H
/** \file
* This file contains internal definitions for file klfmainwin.cpp.
* \internal
*/
#include <QDialog>
#include <QFile>
#include <QString>
#include <QByteArray>
#include <QLabel>
#include <QImageReader>
#include <QBuffer>
#include <QFileInfo>
#include <QMessageBox>
#include <QTextCodec>
#include <klfutil.h>
#include <klfdatautil.h>
#include <klflatexpreviewthread.h>
#include "klflibview.h"
#include "klfmain.h"
#include "klfsettings.h"
#include "klfmime.h"
#include "klfmainwin.h"
#if defined(KLF_WS_MAC)
#include "macosx/klfmacclipboard.h"
#elif defined(KLF_WS_WIN)
#include "mswin/klfwinclipboard.h"
#else
// nothing to do on X11
#endif
#include <ui_klfaboutdialog.h>
#include <ui_klfwhatsnewdialog.h>
/** \internal */
class KLFHelpDialogCommon
{
public:
KLFHelpDialogCommon(const QString& baseFName) : pBaseFName(baseFName) { }
virtual ~KLFHelpDialogCommon() { }
virtual void addExtraText(const QString& htmlSnipplet)
{
pHtmlExtraSnipplets << htmlSnipplet;
}
virtual QString getFullHtml()
{
QString html;
QString fn = klfFindTranslatedDataFile(pBaseFName, ".html");
QFile f(fn);
f.open(QIODevice::ReadOnly);
html = QString::fromUtf8(f.readAll());
klfDbg( "read from file="<<fn<<" the HTML code=\n"<<html ) ;
const QString marker = QLatin1String("<!--KLF_MARKER_INSERT_SPOT-->");
int k;
for (k = 0; k < pHtmlExtraSnipplets.size(); ++k)
html.replace(marker, pHtmlExtraSnipplets[k]+"\n"+marker);
klfDbg( "new HTML is:\n"<<html ) ;
// replace some general recognized "macros"
html.replace("<!--KLF_VERSION-->", KLF_VERSION_STRING);
return html;
}
protected:
QString pBaseFName;
QStringList pHtmlExtraSnipplets;
};
/** \internal */
class KLFAboutDialog : public QDialog, public KLFHelpDialogCommon
{
Q_OBJECT
signals:
void linkActivated(const QUrl&);
public:
KLFAboutDialog(QWidget *parent) : QDialog(parent), KLFHelpDialogCommon("about")
{
u = new Ui::KLFAboutDialog;
u->setupUi(this);
connect(u->txtDisplay, SIGNAL(anchorClicked(const QUrl&)),
this, SIGNAL(linkActivated(const QUrl&)));
}
virtual ~KLFAboutDialog() { }
virtual void show()
{
u->txtDisplay->setHtml(getFullHtml());
QDialog::show();
// refresh our style sheet
setStyleSheet(styleSheet());
}
private:
Ui::KLFAboutDialog *u;
};
/** \internal */
class KLFWhatsNewDialog : public QDialog, public KLFHelpDialogCommon
{
Q_OBJECT
signals:
void linkActivated(const QUrl&);
public:
KLFWhatsNewDialog(QWidget *parent)
: QDialog(parent),
KLFHelpDialogCommon(QString("whats-new-%1.%2").arg(klfVersionMaj()).arg(klfVersionMin()))
{
u = new Ui::KLFWhatsNewDialog;
u->setupUi(this);
connect(u->txtDisplay, SIGNAL(anchorClicked(const QUrl&)),
this, SIGNAL(linkActivated(const QUrl&)));
}
virtual ~KLFWhatsNewDialog() { }
virtual void show()
{
u->txtDisplay->setHtml(getFullHtml());
QDialog::show();
// refresh our style sheet
setStyleSheet(styleSheet());
}
private:
Ui::KLFWhatsNewDialog *u;
};
// -------------------------------------------
#ifdef KLF_WS_MAC
void klf_mac_win_show_without_activating(QWidget *w);
#endif
/** \internal */
class KLFMainWinPopup : public QLabel
{
Q_OBJECT
public:
KLFMainWinPopup(KLFMainWin *mainwin)
: QLabel(mainwin, Qt::Window|Qt::FramelessWindowHint|Qt::CustomizeWindowHint|
Qt::WindowStaysOnTopHint
#ifdef KLF_WS_X11
|Qt::X11BypassWindowManagerHint
#endif
),
_mainWin(mainwin)
{
setObjectName("KLFMainWinPopup");
setFocusPolicy(Qt::NoFocus);
QWidget *frmMain = mainwin->findChild<QWidget*>("frmMain");
if (frmMain)
setGeometry(QRect(mainwin->geometry().topLeft()+QPoint(25,mainwin->height()*2/3),
QSize(frmMain->width()+15, 0)));
setProperty("klfTopLevelWidget", QVariant(true));
setAttribute(Qt::WA_StyledBackground, true);
setStyleSheet(mainwin->window()->styleSheet());
setMargin(0);
QFont f = font();
f.setPointSize(QFontInfo(f).pointSize() - 1);
setFont(f);
setWordWrap(true);
#ifdef KLF_WS_X11
setAttribute(Qt::WA_X11DoNotAcceptFocus, true);
#endif
setAttribute(Qt::WA_ShowWithoutActivating, true);
connect(this, SIGNAL(linkActivated(const QString&)),
this, SLOT(internalLinkActivated(const QString&)));
connect(this, SIGNAL(linkActivated(const QUrl&)),
mainwin, SLOT(helpLinkAction(const QUrl&)));
}
virtual ~KLFMainWinPopup() { }
bool hasMessages() { return (bool)msgKeys.size(); }
QStringList messageKeys() { return msgKeys; }
signals:
void linkActivated(const QUrl& url);
public slots:
/** Displays the message \c msgText in the label. \c msgKey is arbitrary
* and may be used to remove the message with removeMessage() later on.
*/
void addMessage(const QString& msgKey, const QString& msgText)
{
klfDbg("adding message "<<msgKey<<" -> "<<msgText);
msgKeys << msgKey;
messages << ("<p>"+msgText+"</p>");
updateText();
}
void removeMessage(const QString& msgKey)
{
int i = msgKeys.indexOf(msgKey);
if (i < 0)
return;
msgKeys.removeAt(i);
messages.removeAt(i);
updateText();
}
void show()
{
QLabel::show();
setStyleSheet(styleSheet());
#ifdef KLF_WS_MAC
// klf_mac_win_show_without_activating(this);
_mainWin->activateWindow();
#endif
}
private slots:
void internalLinkActivated(const QString& url)
{
emit linkActivated(QUrl::fromEncoded(url.toLatin1()));
}
void updateText()
{
setText("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\""
" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" />"
"<style type=\"text/css\">\n"
"body { margin: 2px 10px; }\n"
"p { white-space: pre-wrap; padding: 0px; margin: 0px 0px 2px 0px; }\n"
"a, a:link { text-decoration: underline; color: #0000af }\n"
"a:hover { color: #0000ff }\n"
"a:active { color: #ff0000 }\n"
"}\n"
"</style>"
"</head>"
"<body>\n"
+ messages.join("\n") +
"<p style=\"margin-top: 5px\">"
"<a href=\"klfaction:/popup?acceptAll\">"+tr("Accept [<b>Alt-Enter</b>]")+"</a> | "+
" <a href=\"klfaction:/popup_close\">"+tr("Close [<b>Esc</b>]")+"</a> | " +
" <a href=\"klfaction:/popup?configDontShow\">"+tr("Don't Show Again")+"</a></p>"+
"</body></html>" );
resize(width(), sizeHint().height());
}
private:
KLFMainWin *_mainWin;
QStringList msgKeys;
QStringList messages;
};
// -------------------------------------------------
// from klfbackend.cpp
QByteArray klf_escape_ps_string(const QString& v);
class KLFBasicDataOpener : public QObject, public KLFAbstractDataOpener
{
Q_OBJECT
public:
KLFBasicDataOpener(KLFMainWin *mainwin) : QObject(mainwin), KLFAbstractDataOpener(mainwin) { }
virtual ~KLFBasicDataOpener() { }
virtual QStringList supportedMimeTypes()
{
QStringList types;
types << "image/png"
<< "image/jpeg"
<< "text/uri-list"
<< "text/plain"
<< "application/pdf" // new!
<< "application/x-klf-libentries"
<< "application/x-klatexformula"
<< "application/x-klatexformula-db" ;
int k;
QList<QByteArray> fmts = QImageReader::supportedImageFormats();
for (k = 0; k < fmts.size(); ++k) {
types << "image/"+fmts[k].toLower();
types << "image/x-"+fmts[k].toLower();
}
klfDbg("mime types: "<<types) ;
return types;
}
virtual bool canOpenFile(const QString& file)
{
KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
klfDbg("file="<<file) ;
QFile f(file);
bool r = f.open(QIODevice::ReadOnly);
if (!r) {
klfDbg(" ... file cannot be accessed.") ;
return false;
}
if (file.endsWith(".klfcommands")) {
return true;
}
if (file.endsWith(".pdf")) {
/// \todo ONLY IF FILE HAS THE RELEVANT META-INFO. .....
return true;
}
bool isimage = false;
if (isKlfImage(&f, &isimage)) {
klfDbg(" ... is KLF-saved image.") ;
return true;
}
if (isimage) { // no try going further, we can't otherwise read image ...
klfDbg(" ... is a non-KLF image.") ;
return false;
}
QString libscheme = KLFLibBasicWidgetFactory::guessLocalFileScheme(file);
if (!libscheme.isEmpty()) {
klfDbg(" ... libscheme="<<libscheme) ;
return true; // it is a library file
}
// by default, fail
klfDbg(" ... not recognized.") ;
return false;
}
virtual bool canOpenData(const QByteArray& data)
{
QBuffer buf;
buf.setData(data);
buf.open(QIODevice::ReadOnly);
bool isimg = false;
if (data.startsWith("%PDF")) {
if (data.contains("/KLFApplication("))
return true;
return false;
}
if (isKlfImage(&buf, &isimg)) {
return true;
}
if (isimg) { // no try going further, we can't otherwise read image ...
return false;
}
// try to read beginning with a QDataStream to look for a known x-klf-libentries header
QDataStream stream(&buf);
stream.setVersion(QDataStream::Qt_4_4);
QString headerstr;
stream >> headerstr;
if (headerstr == QLatin1String("KLF_LIBENTRIES")) {
return true;
}
// *** see note in openData() for library formats. ***
// don't try to open .klf or .klf.db formats.
// otherwise, we can't recognize data, fail
return false;
}
virtual bool openFile(const QString& file)
{
KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
klfDbg("file="<<file);
QFileInfo fi(file);
if (!fi.exists() || !fi.isReadable()) {
klfDbg(" ... file is not readable") ;
return false;
}
QString ext = fi.suffix().trimmed().toLower();
if (ext == "klfcommands") {
// execute commands
return mainWin()->executeURLCommandsFromFile(file);
}
if (ext == "pdf") {
// read from PDF
return openPDF(file);
}
{ // try to open image
QFile f(file);
bool r = f.open(QIODevice::ReadOnly);
if (!r) {
klfDbg(" ... file cannot be opened") ;
return false;
}
bool isimage = false;
if (tryOpenImageData(&f, &isimage)) {
klfDbg(" ... loaded image data!") ;
return true;
}
if (isimage) { // no try going further, we can't otherwise read image ...
klfDbg(" ... is non-KLF image...") ;
return false;
}
}
// open image failed, try the other formats...
// try to load library file
bool result = mainWin()->openLibFile(file);
klfDbg("mainWin()->openLibFile("<<file<<") returned "<<result) ;
if (result)
return true;
// and otherwise, fail
return false;
}
virtual bool openData(const QByteArray& data, const QString& mimetype)
{
KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
klfDbg("mimetype is "<<mimetype) ;
QBuffer buf;
buf.setData(data);
buf.open(QIODevice::ReadOnly);
if (mimetype == "text/uri-list") {
klfDbg("Opening uri-list") ;
QByteArray line;
QStringList flist;
char sbuf[1024];
qint64 len;
while ((len = buf.readLine(sbuf, sizeof(sbuf))) > 0) {
line = QByteArray(sbuf, len);
line = line.trimmed(); // gnome uses \r\n, and URLs don't have whitespace.
QUrl url = QUrl::fromEncoded(line);
if (url.scheme() != "file") {
qWarning()<<KLF_FUNC_NAME<<": can't open URL "<<url.scheme()<<" (can only open local files)";
continue;
}
flist << klfUrlLocalFilePath(url);
klfDbg("... added file "<<flist.last()) ;
}
if (flist.isEmpty()) {
klfDbg("file list is empty.") ;
return true;
}
return mainWin()->openFiles(flist);
}
if (mimetype == "text/plain") {
if (!mainWin()->currentInputLatex().isEmpty()) {
// do NOT overwrite current editing text with local copy/paste operations
// inside editor!! (i.e. normal editing inside editor will generate an event here)
// Simply put, only paste if the editor is empty!
return false;
}
// mainWin()->loadDefaultStyle(); // this can be annoying if pasting into empty editor...
mainWin()->slotSetLatex(QString::fromLocal8Bit(data));
return true;
}
if (mimetype == "application/pdf") {
// can only open file via GS
return false;
}
bool isimage = false;
if (tryOpenImageData(&buf, &isimage))
return true;
if (isimage) // no try going further, we can't otherwise read image ...
return false;
// drop application/x-klf-libentries
if (tryOpenKlfLibEntries(&buf))
return true;
// otherwise if we paste/drop library entries, the case is more delicate, as it can't be
// just opened in the library browser, as they are not in a file. So for now, fail to open the data
// Possibly, todo: suggest user to create a resource/sub-resource to drop the data into
return false;
}
private:
bool prepareImageReader(QImageReader *imagereader, QImage *img, bool *isImage)
{
*isImage = false;
if (!imagereader->canRead()) {
klfDbg("format "<<imagereader->format()<<": canRead() returned FALSE!") ;
return false;
}
*img = imagereader->read();
if (img->isNull()) {
klfDbg("read() returned a null qimage!") ;
return false;
}
*isImage = true;
klfDbg("format: '"<<imagereader->format().constData()<<"': text keys set: "<<img->textKeys()
<<"; error="<<imagereader->error()
<<"; quality="<<imagereader->quality()
<<"; supportsOption(description)="<<imagereader->supportsOption(QImageIOHandler::Description)
<<"; text('AppVersion')="<<img->text("AppVersion")
) ;
if (!img->text("AppVersion").startsWith("KLatexFormula ") && !img->text("AppVersion").startsWith("KLF ")) {
klfDbg("AppVersion is not set to 'KL[atex]F[ormula] [...]' in image metadata.") ;
return false;
}
// it is a klf-saved image
return true;
}
bool isKlfImage(QIODevice *device, bool *isImage)
{
QList<QByteArray> formatlist = QImageReader::supportedImageFormats();
int k;
QImage img;
QImageReader imagereader;
for (k = 0; k < formatlist.size(); ++k) {
device->seek(0);
imagereader.setFormat(formatlist[k]);
imagereader.setDevice(device);
if (prepareImageReader(&imagereader, &img, isImage))
return true;
}
return false;
}
bool tryOpenImageData(QIODevice *device, bool *isimage)
{
QList<QByteArray> formatlist = QImageReader::supportedImageFormats();
int k;
QImageReader imagereader;
QImage img;
for (k = 0; k < formatlist.size(); ++k) {
device->seek(0);
imagereader.setFormat(formatlist[k]);
imagereader.setDevice(device);
if (!prepareImageReader(&imagereader, &img, isimage))
continue;
// read meta-information
KLFImageLatexMetaInfo metainfo(&img);
QString latex = metainfo.loadField("InputLatex");
KLFStyle style;
style.fg_color = read_color(metainfo.loadField("InputFgColor"));
style.bg_color = read_color(metainfo.loadField("InputBgColor"));
style.mathmode = metainfo.loadField("InputMathMode");
style.preamble = metainfo.loadField("InputPreamble");
style.dpi = metainfo.loadField("InputDPI").toInt();
mainWin()->slotLoadStyle(style);
mainWin()->slotSetLatex(latex);
return true;
}
return false;
}
unsigned long read_color(const QString& text)
{
// 1 2 3 4 5
QRegExp rx1("\\s*rgba?\\s*\\(\\s*(\\d+),\\s*(\\d+),\\s*(\\d+)(\\s*,\\s*(\\d+))?\\s*\\)\\s*");
if (rx1.exactMatch(text)) {
if (rx1.cap(4).isEmpty())
return qRgb(rx1.cap(1).toInt(), rx1.cap(2).toInt(), rx1.cap(3).toInt());
else
return qRgba(rx1.cap(1).toInt(), rx1.cap(2).toInt(), rx1.cap(3).toInt(), rx1.cap(5).toInt());
}
// try named color format
QColor c(text);
return c.rgba();
}
bool openPDF(const QString& fname)
{
if (!QFile::exists(fname)) {
klfWarning("File "<<fname<<" does not exist!") ;
return false;
}
// Execute gs to extract meta-info
KLFBackend::klfSettings s = mainWin()->backendSettings();
KLFFilterProcess p("gs PDF meta-info extraction", &s);
p.addArgv(s.gsexec);
p.setProgramCwd(".");
p.addArgv(QStringList() << "-q" << "-dNOPROMPT" << "-dNODISPLAY" << "-dNOPAUSE");
p.setOutputStdout(true);
// p.setOutputStderr(true);
QByteArray psmetacode =
klf_escape_ps_string(fname) + " (r) file runpdfbegin Trailer /Info knownoget_safe pop "
" {exch " // 'Name, Value' becomes 'Value, Name'
" 64 string cvs print (\\n) print " // print the name, converted to string, along with a newline
" dup " // twice the name
" length 16 string cvs print (\\n) print " // print the string length followed by a newline
" print (\\n) print }" // and print the string itself, followed by a newline.
" forall\n";
klfDbg("PS code is "<<QString::fromLatin1(psmetacode)) ;
QByteArray metaoutput;
bool ok = p.run(psmetacode, QString(), &metaoutput);
klfDbg("got output "<<metaoutput) ;
if (!ok) {
klfWarning("Failed to read PDF meta-information from file "<<fname<<".\n"
"\tError message is "<<p.resultErrorString());
QMessageBox::critical(mainWin(), tr("Error"), tr("Can't read latex equation information from PDF file."));
return false;
}
// parse all info
QMap<QString,QString> pdfmeta;
QBuffer buf(&metaoutput);
if (!buf.open(QIODevice::ReadOnly)) {
klfWarning("Can't open internal buffer!");
return false;
}
QTextCodec *u_codec = QTextCodec::codecForName("UTF-16BE");
QByteArray pdfmetaline;
while (!(pdfmetaline = buf.readLine()).isEmpty()) {
QByteArray key = pdfmetaline.trimmed();
if (key.isEmpty())
continue;
// now, read the value length
bool intok;
QByteArray vallenstr = buf.readLine().trimmed();
int vallen = vallenstr.toInt(&intok);
if (!intok) {
klfWarning("Internal error: expected value length information after key "<<key<<": "<<vallenstr) ;
continue;
}
QByteArray value = buf.read(vallen);
/*QByteArray discardline =*/
buf.readLine(); // discard the following newline.
/*klfDbg("discarding "<<discardline) ;*/
// now we got value.
klfDbg("key="<<key<<" value="<<value) ;
// get now the string value.
QString valstr;
klfDbg("Value[0]=="<<(uchar)value[0]<<" value[1]=="<<(uchar)value[1]<<" 0376="<<(int)(uchar)0376<<".");
if ((uchar)value[0] == (uchar)0376 && (uchar)value[1] == (uchar)0377) {
klfDbg("Unicode marks.");
// unicode marks
valstr = u_codec->toUnicode(value);
} else {
valstr = QString::fromLocal8Bit(value);
}
klfDbg("valstr is "<<klfDataToEscaped(valstr.toLocal8Bit()));
pdfmeta[QString::fromLatin1(key)] = valstr;
}
if (!pdfmeta.contains("KLFApplication")) {
klfWarning("The PDF file "<<fname<<" doesn't seem to have KLatexFormula meta-information.");
return false;
}
// now, act according to read meta-information
QString latex = pdfmeta.value("KLFInputLatex");
KLFStyle style;
style.fg_color = read_color(pdfmeta.value("KLFInputFgColor"));
style.bg_color = read_color(pdfmeta.value("KLFInputBgColor"));
style.mathmode = pdfmeta.value("KLFInputMathMode");
style.preamble = pdfmeta.value("KLFInputPreamble");
style.dpi = pdfmeta.value("KLFInputDPI").toInt();
//style.fontname = pdfmeta.value("KLFFontName");// font name not saved, but instructions in preamble
style.fontsize = pdfmeta.value("KLFInputFontSize").toInt();
style.vectorscale = pdfmeta.value("KLFInputVectorScale").toDouble();
style.userScript = pdfmeta.value("KLFInputUserScript");
style.userScriptInput = klfLoadVariantFromText(pdfmeta.value("KLFInputUserScriptParams").toLocal8Bit(), "QVariantMap").toMap();
mainWin()->slotLoadStyle(style);
mainWin()->slotSetLatex(latex);
return true;
}
bool tryOpenKlfLibEntries(QIODevice *dev)
{
// if ONE entry -> load that latex and style
// if more entries -> warn user, and fail
QDataStream stream(dev);
stream.setVersion(QDataStream::Qt_4_4);
QString headerstr;
stream >> headerstr;
if (headerstr != QLatin1String("KLF_LIBENTRIES"))
return false;
QVariantMap properties;
KLFLibEntryList entries;
stream >> properties >> entries;
if (entries.size() > 1) {
QMessageBox::critical(mainWin(), tr("Error"),
tr("The data you have request to open contains multiple formulas.\n"
"You may only open one formula into the LaTeX code editor."));
return false;
}
if (entries.size() == 0) {
QMessageBox::critical(mainWin(), tr("Error"),
tr("The data you have request to open contains no formulas."));
return false;
}
mainWin()->restoreFromLibrary(entries[0], KLFLib::RestoreAll);
return true;
}
};
class KLFTexDataOpener : public QObject, public KLFAbstractDataOpener
{
Q_OBJECT
public:
KLFTexDataOpener(KLFMainWin *mainwin)
: QObject(mainwin), KLFAbstractDataOpener(mainwin)
{
}
virtual ~KLFTexDataOpener()
{
}
virtual QStringList supportedMimeTypes()
{
return QStringList();
}
virtual bool canOpenFile(const QString& file)
{
QFileInfo fi(file);
if (fi.suffix() == "tex" || fi.suffix() == "latex" || fi.suffix() == "klftex")
return true;
// not a TeX file
return false;
}
virtual bool canOpenData(const QByteArray& /*data*/)
{
// Dropped files are opened by the basic data opener, which handles "text/uri-list"
// by calling the main window's openFiles()
return false;
}
virtual bool openFile(const QString& file)
{
KLF_DEBUG_BLOCK(KLF_FUNC_NAME) ;
klfDbg("file="<<file);
if (!canOpenFile(file)) {
klfDbg("file is not openable by us: "<<file);
return false;
}
// filter out and parse our special comments
// the rest is LaTeX code to paste
QFile f(file);
if (!f.open(QIODevice::ReadOnly)) {
QMessageBox::critical(mainWin(), tr("Error"), tr("Can't open file %1. Read Error.").arg(file));
return false;
}
QByteArray latexdata;
QByteArray styledata;
KLFStyle style;
QByteArray line;
while (!(line = f.readLine()).isNull()) {
// see if it is one of our special comments
if (line.startsWith("%%KLF:style: ")) {
// extract style data line
styledata += line.mid(strlen("%%KLF:style: "));
} else if (line.startsWith("%%KLF:")) {
// ignore this unused KLF comment
} else {
// LaTeX line
latexdata += line;
}
}
bool ok = klfLoad(styledata, &style); //,"XML"); ... format is guessed from data
if (!ok) {
klfWarning("Unable to load style from comment data: "<<styledata) ;
}
mainWin()->slotLoadStyle(style);
mainWin()->slotSetLatex(QString::fromLocal8Bit(latexdata));
return true;
}
virtual bool openData(const QByteArray& /*data*/, const QString& /*mimetype*/)
{
return false;
}
};
// --------------------------------------------------------------------------
struct KLFMainWinPrivate : public QObject
{
Q_OBJECT
public:
KLF_PRIVATE_QOBJ_HEAD(KLFMainWin, QObject)
{
pMacOSXMenu = NULL;
pCheckForUpdatesAction = NULL;
mLibBrowser = NULL;
mLatexSymbols = NULL;
mStyleManager = NULL;
mSettingsDialog = NULL;
mAboutDialog = NULL;
mWhatsNewDialog = NULL;
mPopup = NULL;
pMacOSXMenu = NULL;
pCheckForUpdatesAction = NULL;
mShortcutNextParenType = NULL;
mShortcutNextParenModifierType = NULL;
mHistoryLibResource = NULL;
mStyleMenu = NULL;
pLatexPreviewThread = NULL;
pContLatexPreview = NULL;
pUserScriptSettings = NULL;
pExporterManager = NULL;
#if defined(KLF_WS_MAC)
macFlavorsConverter = NULL;
#elif defined(KLF_WS_WIN)
winFormatsConverter = NULL;
#else
// no special needs on X11
#endif
pCmdIface = NULL;
is_quitting = false;
qapp_quit_called = false;
}
KLFLibBrowser *mLibBrowser;
KLFLatexSymbols *mLatexSymbols;
KLFStyleManager *mStyleManager;
KLFSettings *mSettingsDialog;
KLFAboutDialog *mAboutDialog;
KLFWhatsNewDialog *mWhatsNewDialog;
KLFMainWinPopup *mPopup;
QMenuBar *pMacOSXMenu;
QAction *pCheckForUpdatesAction;
QShortcut * mShortcutNextParenType;
QShortcut * mShortcutNextParenModifierType;
/** \internal */
struct HelpLinkAction {
HelpLinkAction(const QString& p, QObject *obj, const char *func, bool param)
: path(p), reciever(obj), memberFunc(func), wantParam(param) { }
QString path;
QObject *reciever;
QByteArray memberFunc;
bool wantParam;
};
QList<HelpLinkAction> mHelpLinkActions;
KLFLibResourceEngine *mHistoryLibResource;
KLFStyleList styles;
bool try_load_style_list(const QString& fileName);
QMenu *mStyleMenu;
bool loadedlibrary;
bool firstshow;
KLFBackend::klfSettings settings; // settings we pass to KLFBackend
bool settings_altered;
KLFBackend::klfOutput output; // output from KLFBackend
/** If TRUE, then the output contained in _output is up-to-date, meaning that we favor displaying
* _output.result instead of the image given by mPreviewBuilderThread. */
bool evaloutput_uptodate;
/** The Thread that will create real-time previews of formulas. */
KLFLatexPreviewThread *pLatexPreviewThread;
KLFContLatexPreview *pContLatexPreview;
QLabel *mExportMsgLabel;
void showExportMsgLabel(const QString& msg, int timeout = 3000);
int pExportMsgLabelTimerId;
KLFUserScriptSettings * pUserScriptSettings;
QHash<QString,QWidget*> userScriptInputWidgets;
QString userScriptCurrentInfo;
QWidget * getUserScriptInputWidget(const QString& uifile);
QVariantMap collectUserScriptInput() const;
/**
* Use \ref currentInputState() instead for "public" use.
*
* Returns the input corresponding to the current GUI state. If \c isFinal is TRUE, then
* the input data may be "remembered" as used (the exact effect depends on the setting), eg.
* math mode is memorized into combo box choices. Typically \c isFinal is TRUE when called
* from slotEvaluate() and FALSE when called to update the preview builder thread. */
KLFBackend::klfInput collectInput(bool isFinal);
QList<QAction*> pExportProfileQuickMenuActionList;
bool ignore_close_event;
bool is_quitting;
bool qapp_quit_called;
// /** "last" window status flags are used in eventFilter() to detect individual dialog
// * geometries resetting */
// QHash<QWidget*,bool> pLastWindowShownStatus;
// QHash<QWidget*,QRect> pLastWindowGeometries;
// /** "saved" window status flags are used in hideEvent() to save the individual dialog visible
// * states, as the "last" status flags will be overridden by all the windows hiding. */
// QHash<QWidget*,bool> pSavedWindowShownStatus;
QString widgetstyle;
void getMissingCmdsFor(const QString& symbol, QStringList * missingCmds, QString *guiText,
bool wantHtmlText = true);
KLFExporterManager * pExporterManager;
QList<KLFAbstractDataOpener*> pDataOpeners;
KLFMimeExportProfileManager pMimeExportProfileManager;
#if defined(KLF_WS_MAC)
KLFMacPasteboardMime * macFlavorsConverter;
#elif defined(KLF_WS_WIN)
KLFWinClipboard * winFormatsConverter;
#else
// no special needs on X11
#endif
KLFCmdIface *pCmdIface;
QVariantMap parseLatexEditPosParenInfo(KLFLatexEdit *editor, int pos);
struct LatexFontDef
{
QString identifier;
QString title;
QString latexdefs;
LatexFontDef(const QString& identifier_ = QString(), const QString& title_ = QString(),
const QString& latexdefs_ = QString())
: identifier(identifier_), title(title_), latexdefs(latexdefs_)
{
}
};
QList<LatexFontDef> pLatexFontDefs;
void reloadLatexFontDefs();
signals:
void saveApplicationState(QSettings * settings);
public slots: // .. but in private API
// private : only as slot to an action containing the style # as user data
void slotLoadStyleAct();
void slotDetailsSideWidgetShown(bool shown);
/** controls the enabled state of the 'see larger preview button' widget */
void slotSetViewControlsEnabled(bool enabled);
/** controls the enabled state of the DRAG/COPY/SAVE & Format widgets */
void slotSetSaveControlsEnabled(bool enabled);
void slotOpenHistoryLibraryResource();
void refreshShowCorrectClearButton();
void refreshExportTypesMenu();
void refreshStylePopupMenus();
void slotLibraryButtonRefreshState(bool on);
void slotSymbolsButtonRefreshState(bool on);
void slotPresetDPISender();
void showRealTimeReset();
void showRealTimePreview(const QImage& preview, const QImage& largePreview);
void showRealTimeError(const QString& errorstr, int errcode);
QSize calcPreviewSize();
void updatePreviewThreadInput();
void updatePreviewThreadSettings();
void displayError(const QString& errormsg);
void slotNewSymbolTyped(const QString& symbol);
void slotPopupClose();
void slotPopupAction(const QUrl& helpLinkUrl);
void slotPopupAcceptAll();
void slotEditorContextMenuInsertActions(const QPoint& pos, QList<QAction*> *actionList);
void slotInsertMissingPackagesFromActionSender();
void slotChangeParenFromActionSender();
void slotChangeParenFromVariantMap(const QVariantMap& data);
void slotCycleParenModifiers(bool forward = true);
void slotCycleParenModifiersBack() { slotCycleParenModifiers(false); }
void slotCycleParenTypes(bool forward = true);
void slotCycleParenTypesBack() { slotCycleParenTypes(false); }
void slotEncloseRegionInDelimiterFromActionSender();
void slotEncloseRegionInDelimiter(const QVariantMap& vmap);
void latexEditReplace(int pos, int len, const QString& text);
void slotUserScriptSet(int index);
void slotUserScriptShowInfo();
void slotUserScriptDisableInputs(KLFUserScriptInfo * info);
};
#endif