-------- Original-Nachricht -------- > Datum: Sat, 6 Jun 2009 14:33:46 +0200 > Von: Pavel Sanda <sa...@lyx.org> > An: lyx-devel@lists.lyx.org > Betreff: Re: GuiProgess
> Peter Kuemmel wrote: > > > > fixed, it was a QtGui header. > > > > > > don't beat me, i'm innocent :) > > > > Have you removed the new files (git -f clean) before patching again? > > removing the new files and adding them back helped indeed. > so you can beat me :D > > > back to the patch - i didn't get what you intend with this splash? For long operations lyx is simply death, and the idea was to show at least a bit of information what's going on. > > problems: > * version control is broken - try for example: > 1. load lfuns.lyx from svn tree > 2. try 'check out for edit' > 3. file disappears Yes this is a problem, all relays on one single thread. > > * output widget is reset after each process. this way viewing of eg > postscript > doesn't show latex translation but only launching gv. instead of reset > we only put some delimiter in the output? this is no probem, the patch should only shaw what is possible. > > * output widget has set too high y-coord as minimun (can be sorted later, > very probably duplicateof the same bug with source code widget. > needed delicated patch iirc.) Also the menu entry is maybe not optimal. Attached an updated patch which adds some progress information code in Buffer, but it doesn't work because of all the other calls (svn). Patch is tested with autotools. Peter > > pavel -- GRATIS für alle GMX-Mitglieder: Die maxdome Movie-FLAT! Jetzt freischalten unter http://portal.gmx.net/de/go/maxdome01
Index: src/frontends/qt4/GuiProgress.cpp =================================================================== --- src/frontends/qt4/GuiProgress.cpp (Revision 0) +++ src/frontends/qt4/GuiProgress.cpp (Revision 0) @@ -0,0 +1,205 @@ +// -*- 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 <config.h> + +#include "GuiProgress.h" + +#include "qt_helpers.h" + +#include "support/Systemcall.h" + +#include <QApplication> +#include <QDebug> + + +namespace lyx { +namespace frontend { + + +static void processEvents() +{ + // 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); +} + + +GuiProgress::GuiProgress(GuiView & parent, Qt::DockWidgetArea area, + Qt::WindowFlags flags) : DockView(parent, "progress", "External tools output", area, flags) +{ + setWindowTitle(qt_("External process monitoring")); + setWidget(&text_edit); + text_edit.setReadOnly(true); +} + + +void GuiProgress::progessStarted() +{ + appendMessage("Process successfully started\n"); +} + + +void GuiProgress::progessFinished() +{ +} + + +void GuiProgress::appendMessage(QString const & msg) +{ + text_edit.insertPlainText(msg); + text_edit.ensureCursorVisible(); + processEvents(); +} + + +void GuiProgress::appendError(QString const & msg) +{ + appendMessage(msg); +} + + +void GuiProgress::clearMessages() +{ + text_edit.clear(); + processEvents(); +} + + +void GuiProgress::showEvent(QShowEvent*) +{ + // don't show splash when progress window is visible + support::ProgressInterface::setInstance(this); +} + + +void GuiProgress::hideEvent(QHideEvent*) +{ + // show splash when no progress window is visible + support::ProgressInterface::setInstance(GuiProgressSplash::instance()); +} + + +void GuiProgress::update() +{ + processEvents(); +} + + + +Dialog * createGuiProgress(GuiView & lv) +{ + GuiView & guiview = static_cast<GuiView &>(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 +} + + + +GuiProgressSplash::GuiProgressSplash() : + QSplashScreen(QPixmap(":/images/banner.png"), Qt::WindowStaysOnTopHint ), + show_counter(0) +{ + wait.setSingleShot(true); + // wait before show + wait.setInterval(3000); + connect(&wait, SIGNAL(timeout()), this, SLOT(showSplash()), Qt::DirectConnection); +} + +void GuiProgressSplash::showSplash() +{ + show(); + processEvents(); +} + + +void GuiProgressSplash::progessStarted() +{ + show_counter++; + if (!wait.isActive()) { + // does not work if we block the gui thread + // therefore call call update() + wait.start(); + } + processEvents(); +} + + +void GuiProgressSplash::progessFinished() +{ + if (show_counter > 0) + show_counter--; + if (show_counter == 0) { + wait.stop(); + hide(); + } +} + + +void GuiProgressSplash::mousePressEvent(QMouseEvent *) +{ + //overwrite hide from QSplashScreen ? + hide(); +} + + + +void GuiProgressSplash::update() +{ + processEvents(); +} + + +void GuiProgressSplash::appendMessage(QString const & msg) +{ + QStringList lines = msg.split("\n"); + while (lines.last().isEmpty() && !lines.isEmpty()) { + lines.pop_back(); + } + showMessage(lines.last(), Qt::AlignLeft | Qt::AlignBottom); + processEvents(); +} + + +void GuiProgressSplash::appendError(QString const & msg) +{ + appendMessage(msg); +} + + +void GuiProgressSplash::clearMessages() +{ + showMessage(QString(), Qt::AlignLeft | Qt::AlignBottom); + processEvents(); +} + +GuiProgressSplash* GuiProgressSplash::splash_instance = 0; + +void GuiProgressSplash::setInstance(GuiProgressSplash* splash) +{ + splash_instance = splash; +} + +GuiProgressSplash* GuiProgressSplash::instance() +{ + return splash_instance; +} + + +} // namespace frontend +} // namespace lyx + +#include "moc_GuiProgress.cpp" \ No newline at end of file Index: src/frontends/qt4/GuiView.cpp =================================================================== --- src/frontends/qt4/GuiView.cpp (Revision 29992) +++ src/frontends/qt4/GuiView.cpp (Arbeitskopie) @@ -27,6 +27,7 @@ #include "GuiToolbar.h" #include "Menus.h" #include "TocModel.h" +#include "GuiProgress.h" #include "qt_helpers.h" @@ -69,6 +70,7 @@ #include "support/os.h" #include "support/Package.h" #include "support/Timeout.h" +#include "support/ProgressInterface.h" #include <QAction> #include <QApplication> @@ -173,6 +175,10 @@ stack_widget_->addWidget(bg_widget_); stack_widget_->addWidget(splitter_); setBackground(); + + splash_ = new GuiProgressSplash; + GuiProgressSplash::setInstance(splash_); + support::ProgressInterface::setInstance(splash_); } ~GuiViewPrivate() @@ -180,6 +186,8 @@ delete splitter_; delete bg_widget_; delete stack_widget_; + support::ProgressInterface::setInstance(0); + delete splash_; } QMenu * toolBarPopup(GuiView * parent) @@ -284,6 +292,8 @@ /// TocModels toc_models_; + + GuiProgressSplash* splash_; }; @@ -1267,7 +1277,9 @@ enable = name == "aboutlyx" || name == "file" //FIXME: should be removed. || name == "prefs" - || name == "texinfo"; + || name == "texinfo" + || name == "texinfo" + || name == "progress"; else if (name == "print") enable = buf->isExportable("dvi") && lyxrc.print_command != "none"; @@ -2423,7 +2435,7 @@ "mathmatrix", "mathspace", "nomenclature", "nomencl_print", "note", "paragraph", "phantom", "prefs", "print", "ref", "sendto", "space", "spellchecker", "symbols", "tabular", "tabularcreate", "thesaurus", "texinfo", -"toc", "view-source", "vspace", "wrap" }; +"toc", "view-source", "vspace", "wrap", "progress" }; char const * const * const end_dialognames = dialognames + (sizeof(dialognames) / sizeof(char *)); @@ -2630,6 +2642,7 @@ Dialog * createGuiVSpace(GuiView & lv); Dialog * createGuiViewSource(GuiView & lv); Dialog * createGuiWrap(GuiView & lv); +Dialog * createGuiProgress(GuiView & lv); Dialog * GuiView::build(string const & name) @@ -2732,6 +2745,8 @@ return createGuiVSpace(*this); if (name == "wrap") return createGuiWrap(*this); + if (name == "progress") + return createGuiProgress(*this); return 0; } Index: src/frontends/qt4/GuiProgress.h =================================================================== --- src/frontends/qt4/GuiProgress.h (Revision 0) +++ src/frontends/qt4/GuiProgress.h (Revision 0) @@ -0,0 +1,104 @@ +// -*- 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 <QTextEdit> +#include <QSplashScreen> +#include <QTimer> + +#include <string> + + +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 progessStarted(); + void progessFinished(); + void appendMessage(QString const &); + void appendError(QString const &); + void clearMessages(); + void update(); + + /// Controller inherited method. + ///@{ + bool initialiseParams(std::string const &) { return true; } + void clearParams() {} + void dispatchParams() {} + bool isBufferDependent() const { return false; } + bool canApply() const { return true; } + bool canApplyToReadOnly() const { return true; } + void updateView() {} + ///@} + + + void showEvent(QShowEvent*); + void hideEvent(QHideEvent*); + +private: + QTextEdit text_edit; +}; + + +class GuiProgressSplash : + public QSplashScreen, + public lyx::support::ProgressInterface +{ + + Q_OBJECT + +public: + GuiProgressSplash(); + + void progessStarted(); + void progessFinished(); + void appendMessage(QString const &); + void appendError(QString const &); + void clearMessages(); + void update(); + + static GuiProgressSplash* instance(); + static void setInstance(GuiProgressSplash*); + +private: + int show_counter; + QTimer wait; + + void mousePressEvent(QMouseEvent *); + + static GuiProgressSplash* splash_instance; + +private Q_SLOTS: + void showSplash(); +}; + +} // namespace frontend +} // namespace lyx + +#endif + Index: src/frontends/qt4/Makefile.am =================================================================== --- src/frontends/qt4/Makefile.am (Revision 29992) +++ src/frontends/qt4/Makefile.am (Arbeitskopie) @@ -107,6 +107,7 @@ GuiPrint.cpp \ GuiPrintindex.cpp \ GuiPrintNomencl.cpp \ + GuiProgress.cpp \ GuiRef.cpp \ GuiSearch.cpp \ GuiSelection.cpp \ @@ -205,6 +206,7 @@ GuiPrint.h \ GuiPrintindex.h \ GuiPrintNomencl.h \ + GuiProgress.h \ GuiRef.h \ GuiSearch.h \ GuiSelection.h \ Index: src/support/Systemcall.cpp =================================================================== --- src/support/Systemcall.cpp (Revision 29992) +++ src/support/Systemcall.cpp (Arbeitskopie) @@ -4,9 +4,9 @@ * Licence details can be found in the file COPYING. * * \author Asger Alstrup - * - * Interface cleaned up by * \author Angus Leeming + * \author Enrico Forestieri + * \author Peter KÃŒmmel * * Full author contact details are available in file CREDITS. */ @@ -19,11 +19,15 @@ #include "support/Systemcall.h" #include "support/SystemcallPrivate.h" #include "support/os.h" +#include "support/ProgressInterface.h" #include <cstdlib> #include <iostream> #include <QProcess> +#include <QCoreApplication> +#include <QEventLoop> +#include <QTimer> #define USE_QPROCESS @@ -42,6 +46,75 @@ } + +class ProgressDummy : public ProgressInterface +{ +public: + ProgressDummy() {} + + void progessStarted() {} + void progessFinished() {} + void appendMessage(QString const &) {} + void appendError(QString const &) {} + void clearMessages() {} + void update() {} +}; + + +static ProgressInterface* progress_instance = 0; + +void ProgressInterface::setInstance(ProgressInterface* p) +{ + progress_instance = p; +} + +ProgressInterface* ProgressInterface::instance() +{ + if (!progress_instance) { + static ProgressDummy dummy; + return &dummy; + } + return progress_instance; +} + + + +ShowProgress::ShowProgress(std::string const & startmessage) +{ + ProgressInterface::instance()->progessStarted(); + ProgressInterface::instance()->appendMessage(startmessage.c_str()); //translate +} + + +ShowProgress::~ShowProgress() +{ + done(); +} + + +void ShowProgress::done() +{ + if (!finishedmessage.empty()) { + ProgressInterface::instance()->appendMessage(finishedmessage.c_str()); + } + ProgressInterface::instance()->progessFinished(); +} + + +void ShowProgress::setEndMessage(std::string const & msg) +{ + finishedmessage = msg; +} + +void ShowProgress::update() +{ + ProgressInterface::instance()->update(); +} + + + + + // Reuse of instance #ifndef USE_QPROCESS int Systemcall::startscript(Starttype how, string const & what) @@ -105,9 +178,17 @@ if (os::is_terminal(os::STDERR)) console.showerr(); + ProgressInterface* progress = ProgressInterface::instance(); + + progress->clearMessages(); + progress->appendMessage("Starting process:\n"); + progress->appendMessage(cmd + "\n"); + QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + + process->start(cmd); if (!process->waitForStarted(3000)) { - LYXERR0("Qprocess " << cmd << " did not start!"); + LYXERR0("QProcess " << cmd << " did not start!"); LYXERR0("error " << process->error()); LYXERR0("state " << process->state()); LYXERR0("status " << process->exitStatus()); @@ -118,16 +199,26 @@ return 0; } - if (!process->waitForFinished(180000)) { - LYXERR0("Qprocess " << cmd << " did not finished!"); + // on Linux waitForFinished does not return when we call QApplication::processEvents() + QTimer timeout; + timeout.setSingleShot(true); + timeout.setInterval(180000); + QEventLoop loop; + QObject::connect(&timeout, SIGNAL(timeout()), &loop, SLOT(quit())); + QObject::connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), &loop, SLOT(quit())); + timeout.start(); + loop.exec(); + if (!timeout.isActive()) { + LYXERR0("QProcess " << cmd << " did not finished!"); LYXERR0("error " << process->error()); LYXERR0("state " << process->state()); LYXERR0("status " << process->exitStatus()); return 20; } + int const exit_code = process->exitCode(); if (exit_code) { - LYXERR0("Qprocess " << cmd << " finished!"); + LYXERR0("QProcess " << cmd << " finished!"); LYXERR0("exitCode " << process->exitCode()); LYXERR0("error " << process->error()); LYXERR0("state " << process->state()); @@ -145,6 +236,7 @@ process->readAllStandardError().data())); killProcess(process); + return exit_code; } @@ -154,6 +246,11 @@ { connect(proc, SIGNAL(readyReadStandardOutput()), SLOT(stdOut())); connect(proc, SIGNAL(readyReadStandardError()), SLOT(stdErr())); + connect(proc, SIGNAL(error(QProcess::ProcessError)), + SLOT(processError(QProcess::ProcessError))); + connect(proc, SIGNAL(started()), this, SLOT(processStarted())); + connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), + SLOT(processFinished(int, QProcess::ExitStatus))); } @@ -185,6 +282,7 @@ outdata_[outindex_] = '\0'; outindex_ = 0; cout << outdata_; + ProgressInterface::instance()->appendMessage(QString::fromLocal8Bit(outdata_)); } } } @@ -202,11 +300,72 @@ errdata_[errindex_] = '\0'; errindex_ = 0; cerr << errdata_; + ProgressInterface::instance()->appendError(QString::fromLocal8Bit(errdata_)); } } } } + +void ConOut::processError(QProcess::ProcessError err) +{ + QString message; + switch (err) { + case QProcess::FailedToStart: + message = "The process failed to start. Either the invoked program is missing, " + "or you may have insufficient permissions to invoke the program."; + break; + case QProcess::Crashed: + message = "The process crashed some time after starting successfully."; + break; + case QProcess::Timedout: + message = "The process timed out. It might be restarted automatically."; + break; + case QProcess::WriteError: + message = "An error occurred when attempting to write to the process-> For example, " + "the process may not be running, or it may have closed its input channel."; + break; + case QProcess::ReadError: + message = "An error occurred when attempting to read from the process-> For example, " + "the process may not be running."; + break; + case QProcess::UnknownError: + default: + message = "An unknown error occured."; + break; + } + ProgressInterface::instance()->appendMessage("\nThe process failed: " + message + '\n'); + ProgressInterface::instance()->progessFinished(); +} + + +void ConOut::processStarted() +{ + ProgressInterface::instance()->progessStarted(); +} + + +void ConOut::processFinished(int, QProcess::ExitStatus status) +{ + ProgressInterface* progress = ProgressInterface::instance(); + + QString message; + switch (status) { + case QProcess::NormalExit: + message = "The process exited normally."; + break; + case QProcess::CrashExit: + message = "The process crashed."; + break; + default: + message = "Unknown exit state."; + break; + } + progress->appendMessage("Process finished: " + message + '\n'); + progress->progessFinished(); +} + + #include "moc_SystemcallPrivate.cpp" #endif Index: src/support/Systemcall.h =================================================================== --- src/support/Systemcall.h (Revision 29992) +++ src/support/Systemcall.h (Arbeitskopie) @@ -20,6 +20,7 @@ namespace lyx { namespace support { + /** * An instance of Class Systemcall represents a single child process. * @@ -43,6 +44,8 @@ * by spaces. */ int startscript(Starttype how, std::string const & what); + +private: }; } // namespace support Index: src/support/ProgressInterface.h =================================================================== --- src/support/ProgressInterface.h (Revision 0) +++ src/support/ProgressInterface.h (Revision 0) @@ -0,0 +1,62 @@ +// -*- 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 + +#include <string> + +class QString; + +namespace lyx { +namespace support { + + +class ProgressInterface +{ +public: + virtual ~ProgressInterface() {} + + virtual void progessStarted() = 0; + virtual void progessFinished() = 0; + virtual void appendMessage(QString const &) = 0; + virtual void appendError(QString const &) = 0; + virtual void clearMessages() = 0; + virtual void update() = 0; + + static void setInstance(ProgressInterface*); + static ProgressInterface* instance(); + +protected: + ProgressInterface() {} +}; + + +class ShowProgress +{ +public: + ShowProgress(std::string const & startmessage); + ~ShowProgress(); + + void setEndMessage(std::string const & msg); + void done(); + void update(); + +private: + std::string finishedmessage; +}; + + +} // namespace support +} // namespace lyx + +#endif // LYX_SUPPORT_PROGRESSINTERFACE_H + Index: src/support/SystemcallPrivate.h =================================================================== --- src/support/SystemcallPrivate.h (Revision 29992) +++ src/support/SystemcallPrivate.h (Arbeitskopie) @@ -14,7 +14,7 @@ #include <QObject> -class QProcess; +#include <QProcess> namespace lyx { namespace support { @@ -58,6 +58,9 @@ public Q_SLOTS: void stdOut(); void stdErr(); + void processError(QProcess::ProcessError); + void processStarted(); + void processFinished(int, QProcess::ExitStatus status); }; } // namespace support Index: src/support/Makefile.am =================================================================== --- src/support/Makefile.am (Revision 29992) +++ src/support/Makefile.am (Arbeitskopie) @@ -77,6 +77,7 @@ Path.h \ Package.cpp \ Package.h \ + ProgressInterface.h \ qstring_helpers.cpp \ qstring_helpers.h \ socktools.cpp \ Index: src/Buffer.cpp =================================================================== --- src/Buffer.cpp (Revision 29992) +++ src/Buffer.cpp (Arbeitskopie) @@ -101,6 +101,7 @@ #include "support/Systemcall.h" #include "support/textutils.h" #include "support/types.h" +#include "support/ProgressInterface.h" #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> @@ -590,6 +591,8 @@ // Returns true if "\end_document" is not read (Asger) bool Buffer::readDocument(Lexer & lex) { + ShowProgress progress("Loading document"); + ErrorList & errorList = d->errorLists["Parse"]; errorList.clear(); @@ -603,6 +606,7 @@ LASSERT(paragraphs().empty(), /**/); readHeader(lex); + progress.update(); if (params().outputChanges) { bool dvipost = LaTeXFeatures::isAvailable("dvipost"); @@ -656,8 +660,11 @@ // read main text bool const res = text().read(*this, lex, errorList, d->inset); + progress.update(); updateMacros(); + progress.update(); + updateMacroInstances(); return res; } @@ -744,6 +751,8 @@ bool Buffer::readFile(FileName const & filename) { + ShowProgress progress("Exporting document"); + FileName fname(filename); params().compressed = fname.isZippedFile(); @@ -2759,6 +2768,8 @@ bool Buffer::doExport(string const & format, bool put_in_tempdir, string & result_file) const { + ShowProgress progress("Exporting document"); + string backend_format; OutputParams runparams(¶ms().encoding()); runparams.flavor = OutputParams::LATEX; Index: lib/ui/stdmenus.inc =================================================================== --- lib/ui/stdmenus.inc (Revision 29992) +++ lib/ui/stdmenus.inc (Arbeitskopie) @@ -310,6 +310,7 @@ Item "Split View Into Upper And Lower Half|e" "split-view vertical" Item "Close Tab Group|G" "close-tab-group" Item "Fullscreen|l" "ui-toggle fullscreen" + Item "Show process messages" "dialog-toggle progress" Submenu "Toolbars|b" "toolbars" Separator Documents