diff --git a/development/scons/scons_manifest.py b/development/scons/scons_manifest.py index 54a70a8ee2..351a9228d9 100644 --- a/development/scons/scons_manifest.py +++ b/development/scons/scons_manifest.py @@ -297,7 +297,9 @@ src_support_header_files = Split(''' RandomAccessList.h SignalSlot.h SignalSlotPrivate.h + ProgressInterface.h Systemcall.h + SystemcallPrivate.h Timeout.h Translator.h convert.h @@ -338,6 +340,7 @@ src_support_files = Split(''' Path.cpp SignalSlot.cpp Systemcall.cpp + SystemcallPrivate.cpp Timeout.cpp abort.cpp convert.cpp @@ -755,6 +758,7 @@ src_frontends_qt4_header_files = Split(''' GuiPopupMenu.h GuiPrefs.h GuiPrint.h + GuiProgress.h GuiRef.h GuiSearch.h GuiSelection.h @@ -841,6 +845,7 @@ src_frontends_qt4_files = Split(''' GuiParagraph.cpp GuiPopupMenu.cpp GuiPrefs.cpp + GuiProgress.cpp GuiPrint.cpp GuiRef.cpp GuiSearch.cpp diff --git a/lib/ui/stdmenus.inc b/lib/ui/stdmenus.inc index d108e827de..c7ba324bcb 100644 --- a/lib/ui/stdmenus.inc +++ b/lib/ui/stdmenus.inc @@ -286,6 +286,7 @@ Menuset Item "Fold Math Macro" "math-macro-fold" Separator Item "View Source|S" "dialog-toggle view-source" + Item "View LaTeX Progress|" "dialog-toggle latex-progress" Submenu "Update|U" "view_update" ViewFormats Separator diff --git a/src/Buffer.cpp b/src/Buffer.cpp index bf0a5dced8..ec79c061f0 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -1097,8 +1097,7 @@ void Buffer::writeLaTeXSource(odocstream & os, if (output_preamble) { if (!runparams.nice) { // code for usual, NOT nice-latex-file - os << "\\batchmode\n"; // changed - // from \nonstopmode + os << "\\nonstopmode\n"; d->texrow.newline(); } if (!original_path.empty()) { diff --git a/src/LaTeX.cpp b/src/LaTeX.cpp index 1934894058..2fe5982055 100644 --- a/src/LaTeX.cpp +++ b/src/LaTeX.cpp @@ -415,11 +415,9 @@ int LaTeX::run(TeXErrors & terr) int LaTeX::startscript() { // onlyFilename() is needed for cygwin - string tmp = cmd + ' ' - + quoteName(onlyFilename(file.toFilesystemEncoding())) - + " > " + os::nulldev(); - Systemcall one; - return one.startscript(Systemcall::Wait, tmp); + string tmp = cmd + ' ' + "-max-print-line=200 " + + quoteName(onlyFilename(file.toFilesystemEncoding())); + return Systemcall().startscript(Systemcall::Wait, tmp); } diff --git a/src/frontends/qt4/GuiProgress.cpp b/src/frontends/qt4/GuiProgress.cpp new file mode 100644 index 0000000000..694a45ef8e --- /dev/null +++ b/src/frontends/qt4/GuiProgress.cpp @@ -0,0 +1,64 @@ +// -*- C++ -*- +/** + * \file GuiProgress.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Peter Kümmel + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "GuiProgress.h" + +#include "support/Systemcall.h" + +#include + + +namespace lyx { +namespace frontend { + + +GuiProgress::GuiProgress(GuiView & parent, Qt::DockWidgetArea area, + Qt::WindowFlags flags) : DockView(parent, "latex-progress", area, flags) +{ + setWindowTitle(qt_("LaTeX Progress")); + setWidget(&text_edit); + lyx::support::Systemcall::registerProgressInterface(this); +} + + +void GuiProgress::appendMessage(QString const & msg) +{ + text_edit.append(msg); + // QEventLoop::ExcludeUserInputEvents: + // don't allow user inputs while processing a document + // if we allow it, we open will Pandora's Box of multithreading + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); +} + + +void GuiProgress::clearMessages() +{ + text_edit.clear(); +} + + +Dialog * createGuiProgress(GuiView & lv) +{ + GuiView & guiview = static_cast(lv); +#ifdef Q_WS_MACX + // TODO where to show up on the Mac? + //return new GuiProgress(guiview, Qt::RightDockWidgetArea, Qt::Drawer); +#else + return new GuiProgress(guiview, Qt::BottomDockWidgetArea); +#endif +} + +} // namespace frontend +} // namespace lyx + + diff --git a/src/frontends/qt4/GuiProgress.h b/src/frontends/qt4/GuiProgress.h new file mode 100644 index 0000000000..56585582d6 --- /dev/null +++ b/src/frontends/qt4/GuiProgress.h @@ -0,0 +1,62 @@ +// -*- C++ -*- +/** + * \file GuiProgress.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Peter Kümmel + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef GUIPROGRESS_H +#define GUIPROGRESS_H + +#include "support/ProgressInterface.h" + +#include "DockView.h" + +#include + +#include + + +namespace lyx { +namespace frontend { + + +class GuiProgress : + public DockView, + public lyx::support::ProgressInterface +{ + +public: + GuiProgress( + GuiView & parent, ///< the main window where to dock. + Qt::DockWidgetArea area, ///< Position of the dock (and also drawer) + Qt::WindowFlags flags = 0); + + void appendMessage(QString const &); + void clearMessages(); + + /// Controller inherited method. + ///@{ + bool initialiseParams(std::string const & source) { return true; } + void clearParams() {} + void dispatchParams() {} + bool isBufferDependent() const { return true; } + bool canApply() const { return true; } + bool canApplyToReadOnly() const { return true; } + void updateView() {} + ///@} + +private: + QTextEdit text_edit; +}; + + +} // namespace frontend +} // namespace lyx + +#endif + diff --git a/src/frontends/qt4/GuiView.cpp b/src/frontends/qt4/GuiView.cpp index 6f3d42ca8e..42e5e1ea67 100644 --- a/src/frontends/qt4/GuiView.cpp +++ b/src/frontends/qt4/GuiView.cpp @@ -23,6 +23,7 @@ #include "GuiMenubar.h" #include "GuiToolbar.h" #include "GuiToolbars.h" +#include "GuiProgress.h" #include "qt_helpers.h" @@ -1569,7 +1570,7 @@ char const * const dialognames[] = { "thesaurus", #endif -"texinfo", "toc", "href", "view-source", "vspace", "wrap", "listings" }; +"texinfo", "toc", "href", "view-source", "latex-progress", "vspace", "wrap", "listings" }; char const * const * const end_dialognames = dialognames + (sizeof(dialognames) / sizeof(char *)); @@ -1793,6 +1794,7 @@ Dialog * createGuiThesaurus(GuiView & lv); Dialog * createGuiHyperlink(GuiView & lv); Dialog * createGuiVSpace(GuiView & lv); Dialog * createGuiViewSource(GuiView & lv); +Dialog * createGuiProgress(GuiView & lv); Dialog * createGuiWrap(GuiView & lv); @@ -1844,6 +1846,8 @@ Dialog * GuiView::build(string const & name) return createGuiLog(*this); if (name == "view-source") return createGuiViewSource(*this); + if (name == "latex-progress") + return createGuiProgress(*this); if (name == "mathdelimiter") return createGuiDelimiter(*this); if (name == "mathmatrix") diff --git a/src/frontends/qt4/Makefile.am b/src/frontends/qt4/Makefile.am index 8b8650a6a1..8fc0edf271 100644 --- a/src/frontends/qt4/Makefile.am +++ b/src/frontends/qt4/Makefile.am @@ -101,6 +101,7 @@ SOURCEFILES = \ GuiPopupMenu.cpp \ GuiPrefs.cpp \ GuiPrint.cpp \ + GuiProgress.cpp \ GuiRef.cpp \ GuiSearch.cpp \ GuiSelection.cpp \ @@ -187,6 +188,7 @@ MOCHEADER = \ GuiPopupMenu.h \ GuiPrefs.h \ GuiPrint.h \ + GuiProgress.h \ GuiRef.h \ GuiSearch.h \ GuiSelection.h \ diff --git a/src/support/Makefile.am b/src/support/Makefile.am index 3e69f53f00..a2697a4b13 100644 --- a/src/support/Makefile.am +++ b/src/support/Makefile.am @@ -75,6 +75,9 @@ liblyxsupport_la_SOURCES = \ strfwd.h \ Systemcall.cpp \ Systemcall.h \ + SystemcallPrivate.cpp \ + SystemcallPrivate.h \ + ProgressInterface.h \ SignalSlot.cpp \ SignalSlot.h \ SignalSlotPrivate.h \ diff --git a/src/support/ProgressInterface.h b/src/support/ProgressInterface.h new file mode 100644 index 0000000000..1bc980e485 --- /dev/null +++ b/src/support/ProgressInterface.h @@ -0,0 +1,38 @@ +// -*- C++ -*- +/** + * \file ProgressInterface.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Peter Kümmel + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef LYX_SUPPORT_PROGRESSINTERFACE_H +#define LYX_SUPPORT_PROGRESSINTERFACE_H + +class QString; + +namespace lyx { +namespace support { + + +class ProgressInterface +{ +public: + virtual ~ProgressInterface() {} + + virtual void appendMessage(QString const &) = 0; + virtual void clearMessages() = 0; + +protected: + ProgressInterface() {} +}; + + +} // namespace support +} // namespace lyx + +#endif // LYX_SUPPORT_PROGRESSINTERFACE_H + diff --git a/src/support/Systemcall.cpp b/src/support/Systemcall.cpp index e8fbd6404e..bf7192dd42 100644 --- a/src/support/Systemcall.cpp +++ b/src/support/Systemcall.cpp @@ -4,6 +4,7 @@ * Licence details can be found in the file COPYING. * * \author Asger Alstrup + * \author Peter Kümmel * * Interface cleaned up by * \author Angus Leeming @@ -14,37 +15,36 @@ #include #include "support/Systemcall.h" -#include "support/os.h" - -#include - -using std::string; - -#ifndef CXX_GLOBAL_CSTD -using std::system; -#endif +#include "support/SystemcallPrivate.h" +#include "support/ProgressInterface.h" namespace lyx { namespace support { -// Reuse of instance -int Systemcall::startscript(Starttype how, string const & what) +static ProgressInterface* progress_impl = 0; + + +void Systemcall::registerProgressInterface(ProgressInterface* p) { - string command = what; - - if (how == DontWait) { - switch (os::shell()) { - case os::UNIX: - command += " &"; - break; - case os::CMD_EXE: - command = "start /min " + command; - break; - } - } - - return ::system(command.c_str()); + progress_impl = p; } + +ProgressInterface* Systemcall::progress() +{ + return progress_impl; +} + + +int Systemcall::startscript(Starttype how, std::string const & what) +{ + // TODO Reuse of instance? + SystemcallPrivate* process = new SystemcallPrivate; + if (how == Wait) + return process->start(what, true); + return process->start(what, false); +} + + } // namespace support } // namespace lyx diff --git a/src/support/Systemcall.h b/src/support/Systemcall.h index 61ba092a2d..8ed0277c0d 100644 --- a/src/support/Systemcall.h +++ b/src/support/Systemcall.h @@ -5,6 +5,7 @@ * Licence details can be found in the file COPYING. * * \author Asger Alstrup + * \author Peter Kümmel * * Interface cleaned up by * \author Angus Leeming @@ -20,10 +21,12 @@ namespace lyx { namespace support { +class ProgressInterface; + /** * An instance of Class Systemcall represents a single child process. * - * Class Systemcall uses system() to launch the child process. + * Class Systemcall uses SystemcallPrivate to launch the child process. * The user can choose to wait or not wait for the process to complete, but no * callback is invoked upon completion of the child. * @@ -43,6 +46,9 @@ public: * by spaces. */ int startscript(Starttype how, std::string const & what); + + static void registerProgressInterface(ProgressInterface*); + static ProgressInterface* progress(); }; } // namespace support diff --git a/src/support/SystemcallPrivate.cpp b/src/support/SystemcallPrivate.cpp new file mode 100644 index 0000000000..bebe91b845 --- /dev/null +++ b/src/support/SystemcallPrivate.cpp @@ -0,0 +1,115 @@ +// -*- C++ -*- +/** + * \file SystemcallPrivate.cpp + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Peter Kümmel + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include "SystemcallPrivate.h" + +#include "Systemcall.h" +#include "ProgressInterface.h" + +#include "gettext.h" +#include "qstring_helpers.h" + + +namespace lyx { +namespace support { + + +// TODO should we move qt_ to qstring_helpers? +static +QString const qt_(char const * str) +{ + return toqstr(_(str)); +} + + + +SystemcallPrivate::SystemcallPrivate() +{ + ProgressInterface* progress = Systemcall::progress(); + if (progress) { + connect(&process, SIGNAL(readyReadStandardOutput()), this, SLOT(newProcessOutput())); + connect(&process, SIGNAL(started()), this, SLOT(processStarted())); + connect(&process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); + connect(&process, SIGNAL(finished(int, QProcess::ExitStatus)), + this, SLOT(processFinished(int, QProcess::ExitStatus))); + } +} + + +int SystemcallPrivate::start(const std::string& cmd, bool waitForFinished) +{ + ProgressInterface* progress = Systemcall::progress(); + if (progress) { + progress->clearMessages(); + progress->appendMessage(qt_("Starting LaTex with command ")); + progress->appendMessage(cmd.c_str()); + } + + process.setReadChannel(QProcess::StandardOutput); + process.start(cmd.c_str(), QStringList(), QIODevice::ReadOnly); + // wait some seconds until the process has started + process.waitForStarted(10 * 1000); + if (waitForFinished) { + // with waitForFinished(-1); we only get one signal per run + while (process.state() == QProcess::Running) + process.waitForFinished(500); + return process.exitCode(); + } + if (process.state() != QProcess::Running) { + process.kill(); + // TODO this needs more testing + deleteLater(); + return -1; + } + return 0; +} + + +void SystemcallPrivate::newProcessOutput() +{ + ProgressInterface* progress = Systemcall::progress(); + if (progress) { + const QString output = QString::fromLocal8Bit(process.readAllStandardOutput()); + progress->appendMessage(output); + } +} + + +void SystemcallPrivate::processStarted() +{ + ProgressInterface* progress = Systemcall::progress(); + if (progress) { + progress->appendMessage(qt_("LaTex started\n")); + } +} + + +void SystemcallPrivate::processError(QProcess::ProcessError) +{ + ProgressInterface* progress = Systemcall::progress(); + if (progress) { + progress->appendMessage(qt_("LaTex error\n")); + } +} + + +void SystemcallPrivate::processFinished(int, QProcess::ExitStatus) +{ + deleteLater(); +} + + +} // namespace support +} // namespace lyx + +#include "SystemcallPrivate_moc.cpp" diff --git a/src/support/SystemcallPrivate.h b/src/support/SystemcallPrivate.h new file mode 100644 index 0000000000..38d42e21e2 --- /dev/null +++ b/src/support/SystemcallPrivate.h @@ -0,0 +1,51 @@ +// -*- C++ -*- +/** + * \file SystemcallPrivate.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Peter Kümmel + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef LYX_SUPPORT_SYSTEMCALLPRIVATE_H +#define LYX_SUPPORT_SYSTEMCALLPRIVATE_H + +#include +#include + +#include + + +namespace lyx { +namespace support { + +class ProgressInterface; + +class SystemcallPrivate : public QObject +{ + Q_OBJECT + +public: + SystemcallPrivate(); + + // When waitForFinished == true : returns the exit code of the process + // When waitForFinished == false: returns 0 if the process could be started + int start(const std::string& cmd, bool waitForFinished); + +public Q_SLOTS: + void newProcessOutput(); + void processStarted(); + void processError(QProcess::ProcessError); + void processFinished(int, QProcess::ExitStatus); + +private: + QProcess process; +}; + + +} // namespace support +} // namespace lyx + +#endif // LYX_SUPPORT_SYSTEMCALLPRIVATE_H