Logging progress for DRC, introducing 'abstract progress' concept

This commit is contained in:
Matthias Koefferlein
2021-02-07 23:41:53 +01:00
parent 620776fe51
commit 94e6f0f7a6
16 changed files with 418 additions and 119 deletions
+3 -23
View File
@@ -71,13 +71,10 @@ public:
ProgressAdaptor (int verbosity); ProgressAdaptor (int verbosity);
virtual ~ProgressAdaptor (); virtual ~ProgressAdaptor ();
virtual void register_object (tl::Progress *progress);
virtual void unregister_object (tl::Progress *progress);
virtual void trigger (tl::Progress *progress); virtual void trigger (tl::Progress *progress);
virtual void yield (tl::Progress *progress); virtual void yield (tl::Progress *progress);
private: private:
std::list<tl::Progress *> mp_objects;
int m_verbosity; int m_verbosity;
std::string m_progress_text, m_progress_value; std::string m_progress_text, m_progress_value;
}; };
@@ -93,36 +90,19 @@ ProgressAdaptor::~ProgressAdaptor ()
// .. nothing yet .. // .. nothing yet ..
} }
void
ProgressAdaptor::register_object (tl::Progress *progress)
{
mp_objects.push_back (progress); // this keeps the outmost one visible. push_front would make the latest one visible.
}
void
ProgressAdaptor::unregister_object (tl::Progress *progress)
{
for (std::list<tl::Progress *>::iterator k = mp_objects.begin (); k != mp_objects.end (); ++k) {
if (*k == progress) {
mp_objects.erase (k);
return;
}
}
}
void void
ProgressAdaptor::trigger (tl::Progress *progress) ProgressAdaptor::trigger (tl::Progress *progress)
{ {
if (! mp_objects.empty () && mp_objects.front () == progress && tl::verbosity () >= m_verbosity) { if (progress && first () == progress && tl::verbosity () >= m_verbosity) {
std::string text = mp_objects.front ()->desc (); std::string text = progress->desc ();
if (m_progress_text != text) { if (m_progress_text != text) {
tl::info << text << " .."; tl::info << text << " ..";
m_progress_text = text; m_progress_text = text;
} }
std::string value = mp_objects.front ()->formatted_value (); std::string value = progress->formatted_value ();
if (m_progress_value != value) { if (m_progress_value != value) {
tl::info << ".. " << value; tl::info << ".. " << value;
m_progress_value = value; m_progress_value = value;
+15 -1
View File
@@ -498,6 +498,20 @@ module DRC
end end
end end
# %DRC%
# @name warn
# @brief Prints a warning
# @synopsis warn(message)
# Similar to \log, but the message is printed formatted as a warning
def warn(arg)
if @log_file
@log_file.puts("WARNING: " + arg)
else
RBA::Logger::warn(arg)
end
end
# %DRC% # %DRC%
# @name log_file # @name log_file
# @brief Specify the log file where to send to log to # @brief Specify the log file where to send to log to
@@ -1840,7 +1854,7 @@ CODE
def run_timed(desc, obj) def run_timed(desc, obj)
info(desc) log(desc)
# enable progress # enable progress
if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts) if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts)
@@ -25,6 +25,8 @@ module DRC
drc._rdb_index = rdb_index drc._rdb_index = rdb_index
drc._generator = generator drc._generator = generator
drc_progress = RBA::AbstractProgress::new("DRC: " + macro.path)
begin begin
# Set a debugger scope so that our errors end up with the debugger set to the DRC's line # Set a debugger scope so that our errors end up with the debugger set to the DRC's line
@@ -46,6 +48,9 @@ module DRC
# cleans up and creates layout and report views # cleans up and creates layout and report views
drc._finish drc._finish
# unlocks the UI
drc_progress._destroy
end end
timer.stop timer.stop
+21 -19
View File
@@ -201,25 +201,6 @@ Class<tl::Timer> decl_Timer ("tl", "Timer",
// ---------------------------------------------------------------- // ----------------------------------------------------------------
// Progress reporter objects // Progress reporter objects
namespace tl {
template <> struct type_traits<tl::Progress> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
template <> struct type_traits<tl::RelativeProgress> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
template <> struct type_traits<tl::AbsoluteProgress> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
}
namespace gsi namespace gsi
{ {
@@ -247,6 +228,27 @@ Class<tl::Progress> decl_Progress ("tl", "Progress",
"This class has been introduced in version 0.23.\n" "This class has been introduced in version 0.23.\n"
); );
static tl::AbstractProgress *abstract_progress (const std::string &desc)
{
return new tl::AbstractProgress (desc);
}
Class<tl::AbstractProgress> decl_AbstractProgress (decl_Progress, "tl", "AbstractProgress",
gsi::constructor ("new", &abstract_progress, gsi::arg ("desc"),
"@brief Creates an abstract progress reporter with the given description\n"
),
"@brief The abstract progress reporter\n"
"\n"
"The abstract progress reporter acts as a 'bracket' for a sequence of operations which are connected "
"logically. For example, a DRC script consists of multiple operations. An abstract progress reportert "
"is instantiated during the run time of the DRC script. This way, the application leaves the UI open while "
"the DRC executes and log messages can be collected.\n"
"\n"
"The abstract progress does not have a value.\n"
"\n"
"This class has been introduced in version 0.27.\n"
);
static tl::RelativeProgress *rel_progress_2 (const std::string &desc, size_t max) static tl::RelativeProgress *rel_progress_2 (const std::string &desc, size_t max)
{ {
return new tl::RelativeProgress (desc, max); return new tl::RelativeProgress (desc, max);
+22
View File
@@ -200,11 +200,33 @@ LogFile::timeout ()
} }
} }
void
LogFile::set_max_entries (size_t n)
{
QMutexLocker locker (&m_lock);
m_max_entries = n;
while (m_messages.size () > m_max_entries) {
m_messages.pop_front ();
}
}
size_t
LogFile::max_entries () const
{
return m_max_entries;
}
void void
LogFile::add (LogFileEntry::mode_type mode, const std::string &msg, bool continued) LogFile::add (LogFileEntry::mode_type mode, const std::string &msg, bool continued)
{ {
QMutexLocker locker (&m_lock); QMutexLocker locker (&m_lock);
if (m_max_entries == 0) {
return;
}
if (m_messages.size () >= m_max_entries) { if (m_messages.size () >= m_max_entries) {
m_messages.pop_front (); m_messages.pop_front ();
} }
+12
View File
@@ -192,6 +192,18 @@ public slots:
return m_log_receiver; return m_log_receiver;
} }
/**
* @brief Sets the maximum number of entries to show
*
* Setting this value to 0 basically disables the log collection
*/
void set_max_entries (size_t n);
/**
* @brief Gets the maximum number of entries to show
*/
size_t max_entries () const;
private slots: private slots:
void timeout (); void timeout ();
+37 -29
View File
@@ -86,14 +86,13 @@ ProgressReporter::set_progress_bar (lay::ProgressBar *pb)
void void
ProgressReporter::register_object (tl::Progress *progress) ProgressReporter::register_object (tl::Progress *progress)
{ {
if (mp_objects.empty ()) { if (begin () == end ()) {
// to avoid recursions of any kind, disallow any user interaction except // to avoid recursions of any kind, disallow any user interaction except
// cancelling the operation // cancelling the operation
QApplication::instance ()->installEventFilter (this); QApplication::instance ()->installEventFilter (this);
} }
mp_objects.push_back (*progress); // this keeps the outmost one visible. push_front would make the latest one visible. tl::ProgressAdaptor::register_object (progress);
// mp_objects.push_front (progress);
if (m_start_time == tl::Clock () && ! m_pw_visible) { if (m_start_time == tl::Clock () && ! m_pw_visible) {
m_start_time = tl::Clock::current (); m_start_time = tl::Clock::current ();
@@ -104,33 +103,47 @@ ProgressReporter::register_object (tl::Progress *progress)
set_visible (true); set_visible (true);
} }
update_and_yield (); if (progress->is_abstract ()) {
if (mp_pb) {
mp_pb->update_progress (progress);
}
process_events ();
} else {
update_and_yield ();
}
} }
void void
ProgressReporter::unregister_object (tl::Progress *progress) ProgressReporter::unregister_object (tl::Progress *progress)
{ {
progress->unlink (); tl::ProgressAdaptor::unregister_object (progress);
// close or refresh window // close or refresh window
if (mp_objects.empty ()) { if (begin () == end ()) {
if (m_pw_visible) { if (m_pw_visible) {
set_visible (false); set_visible (false);
} }
m_start_time = tl::Clock (); m_start_time = tl::Clock ();
}
update_and_yield (); if (mp_pb) {
mp_pb->update_progress (0);
}
process_events ();
if (mp_objects.empty ()) {
QApplication::instance ()->removeEventFilter (this); QApplication::instance ()->removeEventFilter (this);
} else {
update_and_yield ();
} }
} }
void void
ProgressReporter::trigger (tl::Progress * /*progress*/) ProgressReporter::trigger (tl::Progress * /*progress*/)
{ {
if (! mp_objects.empty ()) { if (begin () != end ()) {
// make dialog visible after some time has passed // make dialog visible after some time has passed
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) { if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
set_visible (true); set_visible (true);
@@ -152,27 +165,22 @@ ProgressReporter::yield (tl::Progress * /*progress*/)
} }
} }
void
ProgressReporter::signal_break ()
{
for (tl::list<tl::Progress>::iterator k = mp_objects.begin (); k != mp_objects.end (); ++k) {
k->signal_break ();
}
}
void void
ProgressReporter::update_and_yield () ProgressReporter::update_and_yield ()
{ {
if (m_pw_visible && ! mp_objects.empty ()) { if (! m_pw_visible) {
if (mp_pb) { return;
mp_pb->update_progress (mp_objects.first ());
QWidget *w = mp_pb->progress_get_widget ();
if (w) {
mp_objects.first ()->render_progress (w);
}
}
process_events (); // Qt4 seems to need this
} }
if (mp_pb && first ()) {
mp_pb->update_progress (first ());
QWidget *w = mp_pb->progress_get_widget ();
if (w) {
first ()->render_progress (w);
}
}
process_events (); // Qt4 seems to need this
} }
void void
@@ -202,8 +210,8 @@ ProgressReporter::set_visible (bool vis)
if (mp_pb) { if (mp_pb) {
if (!vis) { if (!vis) {
mp_pb->progress_remove_widget (); mp_pb->progress_remove_widget ();
} else if (mp_pb->progress_wants_widget () && mp_objects.first ()) { } else if (mp_pb->progress_wants_widget () && first ()) {
mp_pb->progress_add_widget (mp_objects.first ()->progress_widget ()); mp_pb->progress_add_widget (first ()->progress_widget ());
} }
} }
-7
View File
@@ -68,16 +68,9 @@ public:
virtual void yield (tl::Progress *progress); virtual void yield (tl::Progress *progress);
virtual bool eventFilter (QObject *dest, QEvent *event); virtual bool eventFilter (QObject *dest, QEvent *event);
void signal_break ();
void set_progress_bar (lay::ProgressBar *pb); void set_progress_bar (lay::ProgressBar *pb);
bool is_busy () const
{
return !mp_objects.empty ();
}
private: private:
tl::list<tl::Progress> mp_objects;
tl::Clock m_start_time; tl::Clock m_start_time;
lay::ProgressBar *mp_pb; lay::ProgressBar *mp_pb;
bool m_pw_visible; bool m_pw_visible;
+75 -16
View File
@@ -60,7 +60,7 @@ private:
ProgressBarWidget::ProgressBarWidget (QWidget *parent, const char *name) ProgressBarWidget::ProgressBarWidget (QWidget *parent, const char *name)
: QWidget (parent), : QWidget (parent),
m_value (0.0), m_width (64), m_length (0), m_fw (1), m_bw (0) m_value (0.0), m_width (200), m_length (0), m_fw (1), m_bw (0)
{ {
setObjectName (QString::fromUtf8 (name)); setObjectName (QString::fromUtf8 (name));
setMinimumSize (64, 10); setMinimumSize (64, 10);
@@ -135,20 +135,49 @@ ProgressBarWidget::resizeEvent (QResizeEvent *)
// -------------------------------------------------------------------- // --------------------------------------------------------------------
ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full_width) ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool fw)
: QFrame (parent), : QFrame (parent),
mp_widget (0), mp_pr (pr), m_log_file (6, true) mp_widget (0), mp_pr (pr), m_log_file (0, true), m_log_visible (false)
{ {
QVBoxLayout *top_layout = new QVBoxLayout (this); QVBoxLayout *top_layout = new QVBoxLayout (this);
top_layout->addStretch (1); top_layout->addStretch (1);
mp_log_frame = new QFrame (this);
mp_log_frame->setFrameShape (QFrame::NoFrame);
mp_log_frame->hide ();
top_layout->addWidget (mp_log_frame);
QVBoxLayout *log_layout = new QVBoxLayout (mp_log_frame);
QListView *log_view = new QListView (this);
log_view->setModel (&m_log_file);
log_view->setUniformItemSizes (true);
log_layout->addWidget (log_view);
QFrame *attn_frame = new QFrame (this);
attn_frame->setFrameShape (QFrame::NoFrame);
attn_frame->hide ();
log_layout->addWidget (attn_frame);
QHBoxLayout *attn_layout = new QHBoxLayout (attn_frame);
attn_layout->setContentsMargins (0, 0, 0, 0);
QLabel *attn_label1 = new QLabel (attn_frame);
attn_label1->setPixmap (QPixmap (QString::fromUtf8 (":/warn_16.png")));
attn_layout->addWidget (attn_label1);
QLabel *attn_label2 = new QLabel (attn_frame);
attn_label2->setText (tr ("There are errors or warnings"));
attn_layout->addWidget (attn_label2);
attn_layout->addStretch (1);
connect (&m_log_file, SIGNAL (layoutChanged ()), log_view, SLOT (scrollToBottom ()));
connect (&m_log_file, SIGNAL (attention_changed (bool)), attn_frame, SLOT (setVisible (bool)));
QFrame *bar_frame = new QFrame (this); QFrame *bar_frame = new QFrame (this);
top_layout->addWidget (bar_frame); top_layout->addWidget (bar_frame);
QListView *log_list = new QListView (this);
log_list->setModel (&m_log_file);
top_layout->addWidget (log_list);
top_layout->addStretch (1); top_layout->addStretch (1);
// this does not allow the label to control the overall size, so a long string does not hurt: // this does not allow the label to control the overall size, so a long string does not hurt:
@@ -162,12 +191,11 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full
int col = 0; int col = 0;
if (! full_width) { layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Expanding, QSizePolicy::Expanding), 0, col, 1, 1);
layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Expanding, QSizePolicy::Expanding), 0, col, 1, 1); m_left_col = col++;
layout->setColumnStretch (col++, 1);
}
mp_label = new QLabel (bar_frame); mp_label = new QLabel (bar_frame);
layout->setColumnStretch(col, 2);
layout->addWidget (mp_label, 0, col++, 1, 1); layout->addWidget (mp_label, 0, col++, 1, 1);
layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, col++, 1, 1); layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, col++, 1, 1);
@@ -176,7 +204,6 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full
progress_bar_frame->setFrameStyle (QFrame::Box | QFrame::Plain); progress_bar_frame->setFrameStyle (QFrame::Box | QFrame::Plain);
progress_bar_frame->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); progress_bar_frame->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget (progress_bar_frame, 0, col, 1, 1); layout->addWidget (progress_bar_frame, 0, col, 1, 1);
layout->setColumnStretch(col++, 2);
QGridLayout *pbf_layout = new QGridLayout (progress_bar_frame); QGridLayout *pbf_layout = new QGridLayout (progress_bar_frame);
progress_bar_frame->setLayout (pbf_layout); progress_bar_frame->setLayout (pbf_layout);
@@ -196,16 +223,41 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool full
mp_cancel_button->setText (QObject::tr ("Cancel")); mp_cancel_button->setText (QObject::tr ("Cancel"));
layout->addWidget (mp_cancel_button, 0, col++, 1, 1); layout->addWidget (mp_cancel_button, 0, col++, 1, 1);
if (! full_width) { layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Expanding, QSizePolicy::Expanding), 0, col, 1, 1);
layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Expanding, QSizePolicy::Expanding), 0, col, 1, 1); m_right_col = col++;
layout->setColumnStretch (col++, 1);
}
layout->addItem (new QSpacerItem (10, 10, QSizePolicy::Fixed, QSizePolicy::Fixed), 1, 0, 1, col); layout->addItem (new QSpacerItem (10, 10, QSizePolicy::Fixed, QSizePolicy::Fixed), 1, 0, 1, col);
m_widget_col = col; m_widget_col = col;
connect (mp_cancel_button, SIGNAL (clicked ()), this, SLOT (signal_break ())); connect (mp_cancel_button, SIGNAL (clicked ()), this, SLOT (signal_break ()));
set_full_width (fw);
}
void
ProgressWidget::set_log_visible (bool f)
{
if (f != m_log_visible) {
m_log_visible = f;
mp_log_frame->setVisible (f);
set_full_width (m_full_width);
}
}
void
ProgressWidget::set_full_width (bool fw)
{
m_full_width = fw;
bool f = (fw || m_log_visible);
mp_layout->setColumnStretch (m_left_col, f ? 0 : 1);
mp_layout->setColumnStretch (m_right_col, f ? 0 : 1);
}
bool
ProgressWidget::full_width () const
{
return m_full_width;
} }
QWidget * QWidget *
@@ -238,6 +290,13 @@ ProgressWidget::remove_widget ()
void void
ProgressWidget::set_progress (tl::Progress *progress) ProgressWidget::set_progress (tl::Progress *progress)
{ {
if (! progress || progress->is_abstract ()) {
m_log_file.clear ();
m_log_file.set_max_entries (progress ? 1000 : 0);
set_log_visible (progress != 0);
return;
}
bool can_cancel = false; bool can_cancel = false;
std::string text; std::string text;
+10
View File
@@ -37,6 +37,8 @@ class QToolButton;
class QLabel; class QLabel;
class QToolButton; class QToolButton;
class QGridLayout; class QGridLayout;
class QListView;
class QFrame;
namespace tl namespace tl
{ {
@@ -60,6 +62,8 @@ public:
void add_widget (QWidget *widget); void add_widget (QWidget *widget);
void remove_widget (); void remove_widget ();
QWidget *get_widget () const; QWidget *get_widget () const;
void set_full_width (bool fw);
bool full_width () const;
QSize sizeHint () const; QSize sizeHint () const;
@@ -75,6 +79,12 @@ private:
QToolButton *mp_cancel_button; QToolButton *mp_cancel_button;
ProgressReporter *mp_pr; ProgressReporter *mp_pr;
lay::LogFile m_log_file; lay::LogFile m_log_file;
QFrame *mp_log_frame;
bool m_full_width;
int m_left_col, m_right_col;
bool m_log_visible;
void set_log_visible (bool f);
}; };
} }
-2
View File
@@ -409,8 +409,6 @@ namespace
mp_dialog->mark_fetching (m_name); mp_dialog->mark_fetching (m_name);
} }
virtual void register_object (tl::Progress * /*progress*/) { }
virtual void unregister_object (tl::Progress * /*progress*/) { }
virtual void yield (tl::Progress * /*progress*/) { } virtual void yield (tl::Progress * /*progress*/) { }
virtual void trigger (tl::Progress *progress) virtual void trigger (tl::Progress *progress)
+4
View File
@@ -35,6 +35,10 @@ TextProgress::TextProgress (int verbosity)
void TextProgress::update_progress (tl::Progress *progress) void TextProgress::update_progress (tl::Progress *progress)
{ {
if (! progress || progress->is_abstract ()) {
return;
}
std::string text = progress->desc (); std::string text = progress->desc ();
if (m_progress_text != text && tl::verbosity () >= m_verbosity) { if (m_progress_text != text && tl::verbosity () >= m_verbosity) {
tl::info << text << " .."; tl::info << text << " ..";
+3
View File
@@ -34,6 +34,7 @@
#include "tlXMLParser.h" #include "tlXMLParser.h"
#include "tlGlobPattern.h" #include "tlGlobPattern.h"
#include "tlInclude.h" #include "tlInclude.h"
#include "tlProgress.h"
#include "rba.h" #include "rba.h"
#include "pya.h" #include "pya.h"
@@ -1022,6 +1023,8 @@ int Macro::run () const
try { try {
tl::ProgressGarbageCollector progress_gc;
gsi::Interpreter *ip = script_interpreter (interpreter ()); gsi::Interpreter *ip = script_interpreter (interpreter ());
if (ip) { if (ip) {
+80 -1
View File
@@ -46,6 +46,18 @@ ProgressAdaptor::~ProgressAdaptor ()
tl::Progress::register_adaptor (0); tl::Progress::register_adaptor (0);
} }
void
ProgressAdaptor::register_object (Progress *progress)
{
mp_objects.push_back (progress); // this keeps the outmost one visible. push_front would make the latest one visible.
}
void
ProgressAdaptor::unregister_object (Progress *progress)
{
progress->unlink ();
}
void void
ProgressAdaptor::prev (ProgressAdaptor *pa) ProgressAdaptor::prev (ProgressAdaptor *pa)
{ {
@@ -58,6 +70,59 @@ ProgressAdaptor::prev ()
return mp_prev; return mp_prev;
} }
void
ProgressAdaptor::signal_break ()
{
for (tl::list<tl::Progress>::iterator k = mp_objects.begin (); k != mp_objects.end (); ++k) {
k->signal_break ();
}
}
tl::Progress *
ProgressAdaptor::first ()
{
for (tl::list<tl::Progress>::iterator k = mp_objects.begin (); k != mp_objects.end (); ++k) {
if (! k->is_abstract ()) {
return k.operator-> ();
}
}
return 0;
}
// ---------------------------------------------------------------------------------------------
// ProgressGarbageCollector implementation
ProgressGarbageCollector::ProgressGarbageCollector ()
{
tl::ProgressAdaptor *a = tl::Progress::adaptor ();
if (a) {
for (tl::ProgressAdaptor::iterator p = a->begin (); p != a->end (); ++p) {
mp_valid_objects.insert (p.operator-> ());
}
}
}
ProgressGarbageCollector::~ProgressGarbageCollector ()
{
tl::ProgressAdaptor *a = tl::Progress::adaptor ();
if (a) {
for (tl::ProgressAdaptor::iterator p = a->begin (); p != a->end (); ) {
tl::ProgressAdaptor::iterator pn = p;
++pn;
if (mp_valid_objects.find (p.operator-> ()) == mp_valid_objects.end ()) {
a->unregister_object (p.operator-> ());
}
p = pn;
}
}
}
// --------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------
// Progress implementation // Progress implementation
@@ -187,7 +252,21 @@ bool Progress::test(bool force_yield)
} }
// --------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------
// Progress implementation // AbstractProgress implementation
AbstractProgress::AbstractProgress (const std::string &desc)
: tl::Progress (desc)
{
initialize ();
}
AbstractProgress::~AbstractProgress ()
{
shutdown ();
}
// ---------------------------------------------------------------------------------------------
// RelativeProgress implementation
RelativeProgress::RelativeProgress (const std::string &desc, size_t max_count, size_t yield_interval) RelativeProgress::RelativeProgress (const std::string &desc, size_t max_count, size_t yield_interval)
: Progress (desc, yield_interval) : Progress (desc, yield_interval)
+131 -9
View File
@@ -31,12 +31,57 @@
#include "tlTimer.h" #include "tlTimer.h"
#include "tlList.h" #include "tlList.h"
#include <set>
class QWidget; class QWidget;
namespace tl namespace tl
{ {
class Progress; class Progress;
class RelativeProgress;
class AbstractProgress;
class AbsoluteProgress;
template <> struct type_traits<tl::Progress> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
template <> struct type_traits<tl::RelativeProgress> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
template <> struct type_traits<tl::AbstractProgress> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
template <> struct type_traits<tl::AbsoluteProgress> : public type_traits<void> {
typedef tl::false_tag has_copy_constructor;
typedef tl::false_tag has_default_constructor;
};
/**
* @brief A helper class to clean up pending progress objects
*
* Pending progress objects may be created in scripts. If scripts are aborted
* (e.g. in the debugger), progress objects may stay behing a block the application.
* To prevent this, this object keeps track of progress objects created between
* it's constructor and destructor and cleans up the objects created but not
* destroyed.
*/
class TL_PUBLIC ProgressGarbageCollector
{
public:
ProgressGarbageCollector ();
~ProgressGarbageCollector ();
private:
std::set<tl::Progress *> mp_valid_objects;
};
/** /**
* @brief The receivers for progress reports * @brief The receivers for progress reports
@@ -48,20 +93,45 @@ class Progress;
class TL_PUBLIC ProgressAdaptor class TL_PUBLIC ProgressAdaptor
{ {
public: public:
typedef tl::list<tl::Progress>::iterator iterator;
ProgressAdaptor (); ProgressAdaptor ();
virtual ~ProgressAdaptor (); virtual ~ProgressAdaptor ();
virtual void register_object (Progress *progress) = 0; virtual void register_object (Progress *progress);
virtual void unregister_object (Progress *progress) = 0; virtual void unregister_object (Progress *progress);
virtual void trigger (Progress *progress) = 0; virtual void trigger (Progress *progress) = 0;
virtual void yield (Progress *progress) = 0; virtual void yield (Progress *progress) = 0;
void prev (ProgressAdaptor *pa); void prev (ProgressAdaptor *pa);
ProgressAdaptor *prev (); ProgressAdaptor *prev ();
bool is_busy () const
{
return !mp_objects.empty ();
}
tl::Progress *first ();
void signal_break ();
protected:
iterator begin ()
{
return mp_objects.begin ();
}
iterator end ()
{
return mp_objects.end ();
}
private: private:
friend class ProgressGarbageCollector;
ProgressAdaptor *mp_prev; ProgressAdaptor *mp_prev;
tl::list<tl::Progress> mp_objects;
}; };
/** /**
@@ -77,8 +147,6 @@ public:
BreakException () : tl::Exception ("Operation cancelled") { } BreakException () : tl::Exception ("Operation cancelled") { }
}; };
class Progress;
/** /**
* @brief A "progress" reporter class * @brief A "progress" reporter class
* *
@@ -138,6 +206,15 @@ public:
*/ */
virtual double value () const = 0; virtual double value () const = 0;
/**
* @brief Returns true if the progress is an abstract one
*
* Abstract progress objcts don't have a value but mark a section begin executed as a top level progress.
* Technically they will open a channel for the UI - e.g. leaving a progress dialog open while the
* operation is running.
*/
virtual bool is_abstract () const = 0;
/** /**
* @brief Creates a widget that renders the progress graphically * @brief Creates a widget that renders the progress graphically
* *
@@ -217,6 +294,7 @@ protected:
private: private:
friend class ProgressAdaptor; friend class ProgressAdaptor;
friend class ProgressGarbageCollector;
std::string m_desc; std::string m_desc;
std::string m_title; std::string m_title;
@@ -231,6 +309,43 @@ private:
static void register_adaptor (tl::ProgressAdaptor *pa); static void register_adaptor (tl::ProgressAdaptor *pa);
}; };
/**
* @brief The abstract progress
*
* An abstract progress object can be used as a top-level progress object to mark a section
* in an operation flow. This will provide a hint for the UI to leave the progress dialog open
* for example.
*/
class TL_PUBLIC AbstractProgress
: public Progress
{
public:
/**
* @brief Constructor
*/
AbstractProgress (const std::string &desc);
/**
* @brief Destructor
*/
~AbstractProgress ();
/**
* @brief Delivers the current progress as a string (empty for the abstract progress)
*/
std::string formatted_value () const { return std::string (); }
/**
* @brief Delivers the relative progress (0 for the abstract progress)
*/
double value () const { return 0.0; }
/**
* @brief Indicates this progress reporter is abstract
*/
bool is_abstract() const { return true; }
};
/** /**
* @brief A relative progress value * @brief A relative progress value
* *
@@ -253,9 +368,6 @@ public:
*/ */
RelativeProgress (const std::string &desc, size_t max_count = 0, size_t yield_interval = 1000); RelativeProgress (const std::string &desc, size_t max_count = 0, size_t yield_interval = 1000);
/**
* @brief Destructor
*/
~RelativeProgress (); ~RelativeProgress ();
/** /**
@@ -271,6 +383,11 @@ public:
*/ */
double value () const; double value () const;
/**
* @brief Indicates this progress reporter isn't abstract
*/
bool is_abstract() const { return false; }
/** /**
* @brief Set the format of the output. * @brief Set the format of the output.
* *
@@ -345,7 +462,12 @@ public:
*/ */
double value () const; double value () const;
/** /**
* @brief Indicates this progress reporter isn't abstract
*/
bool is_abstract() const { return false; }
/**
* @brief Set the format of the output. * @brief Set the format of the output.
* *
* This is a sprintf format string with the value being * This is a sprintf format string with the value being
-12
View File
@@ -512,8 +512,6 @@ class TL_PUBLIC WorkerProgressAdaptor : public tl::ProgressAdaptor
public: public:
WorkerProgressAdaptor (Worker *worker); WorkerProgressAdaptor (Worker *worker);
virtual void register_object (Progress *progress);
virtual void unregister_object (Progress *progress);
virtual void trigger (Progress *progress); virtual void trigger (Progress *progress);
virtual void yield (Progress *progress); virtual void yield (Progress *progress);
@@ -527,16 +525,6 @@ WorkerProgressAdaptor::WorkerProgressAdaptor (Worker *worker)
// .. nothing yet .. // .. nothing yet ..
} }
void WorkerProgressAdaptor::register_object (Progress * /*progress*/)
{
// .. nothing yet ..
}
void WorkerProgressAdaptor::unregister_object (Progress * /*progress*/)
{
// .. nothing yet ..
}
void WorkerProgressAdaptor::trigger (Progress * /*progress*/) void WorkerProgressAdaptor::trigger (Progress * /*progress*/)
{ {
// .. nothing yet .. // .. nothing yet ..