[rkward-cvs] rkward/rkward/misc rkprogresscontrol.cpp, NONE, 1.1 rkprogresscontrol.h, NONE, 1.1 Makefile.am, 1.11, 1.12

Thomas Friedrichsmeier tfry at users.sourceforge.net
Sun Sep 10 20:12:24 UTC 2006


Update of /cvsroot/rkward/rkward/rkward/misc
In directory sc8-pr-cvs9.sourceforge.net:/tmp/cvs-serv20435

Modified Files:
	Makefile.am 
Added Files:
	rkprogresscontrol.cpp rkprogresscontrol.h 
Log Message:
Add RKProgressControl. This is a unification of RKCancelDialog and RKErrorDialog. The latter two should be replaced and removed

--- NEW FILE: rkprogresscontrol.h ---
/***************************************************************************
                          rkprogresscontol  -  description
                             -------------------
    begin                : Sun Sep 10 2006
    copyright            : (C) 2006 by Thomas Friedrichsmeier
    email                : tfry at users.sourceforge.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
#ifndef RKPROGRESSCONTROL_H
#define RKPROGRESSCONTROL_H

#include <qobject.h>
#include "../rbackend/rcommandreceiver.h"

#include <qstring.h>
#include <qdialog.h>

class QDialog;
class QLabel;
class QTextEdit;
class QVBox;

class RKProgressControlDialog;

/**
This class is a functional combination of the older RKCancelDialog and RKErrorDialog classes. Depending on the selected mode it can be used to allow the user to cancel running actions, to display errors / warning / regular output, only when errors occur or also during normal progress, etc. It provides facilities to get output from an RCommand directly, or you can manually submit output fragments via newOutput and newError.
Note that this class is not a dialog in itself. Rather, a dialog is only created, if / when it is actually needed.
TODO: This and RKwatch should use a common means of displaying the output to achieve a common look and feel.

@author Thomas Friedrichsmeier
*/
class RKProgressControl : public QObject, public RCommandReceiver {
	Q_OBJECT
public:
/** create an RKProgressContol dialog
@param text Text to be shown in the dialog
@param caption caption of the dialog
@param mode_flags a bitwise OR combination of RKProgressControlFlags */
	RKProgressControl (QObject *parent, const QString &text, const QString &caption, int mode_flags);
/** destructor */
	~RKProgressControl ();

/** These flags control the mode of operation. Generally you will use on of the predefined sets (StandardCancel, StandardError, DetailedError, StandardProgress, or CancellableProgress) */
	enum RKProgressControlFlags {
		AllowCancel=1,			 			/**< Show a cancel button. When the cancel button is pressed or the dialog is closed, the signal cancelled () is emitted, and (if invoked that way) doModal returns QDialog::rejected */
		AutoCancelCommands=1024, 	/**< if the user cancels the dialog, automatically cancel all commands previously added via addRCommand () (and not yet finished. Only meaningful if AllowCancel is set as well */
		IncludeErrorOutput=2,			/**< Include erros output in the output shown */
		IncludeRegularOutput=4,		/**< Include regular (no error) output in the output shown */
		RaiseOnError=16,					/**< dialog is shown/raised, when there are errors. Only meaningful, if IncludeErrorOutput is set as well */
		RaiseOnRegularOutput=32,	/**< dialog is also shown/raised, when there is new regular output. Only meaningful, if IncludeRegularOutput is set as well  */
		OutputShownByDefault=64,	/**< the textfield with the output is shown by default, not only when requested by the user. Requires at least one of IncludeErrorOutput or IncludeRegularOutput */
		OutputSwitchable=128,		/**< the textfield with the output can be shown/hidden by the user */
		ShowAtOnce=256,				/**< dialog is shown at once, instead of only when there is an error/output */
		PreventClose=512,				/**< do not accept close events */
		StandardCancel=AllowCancel | ShowAtOnce | OutputSwitchable | PreventClose,
		StandardError=IncludeErrorOutput | RaiseOnError | OutputShownByDefault,
		DetailedError=StandardError | IncludeRegularOutput,
		StandardProgress=DetailedError | OutputSwitchable | RaiseOnRegularOutput,
		CancellableProgress=(StandardProgress | StandardCancel) - (OutputShownByDefault | RaiseOnRegularOutput)
	};

/** show the dialog modal. This will always show the dialog right away
@returns true, if ended by done () or false if it was cancelled / closed */
	bool doModal (bool autodelete);
/** initialize the dialog non modal. The dialog is only shown if needed or set in the constructor flags */
	void doNonModal (bool autodelete);

/** you don't need this, unless you feed regular output to the dialog using newOutput. */
	void resetOutput ();
/** add a command to listen to. Warning: You will always first call addRCommand, then submit the command to RInterface, never the other way around. Else there could be a race condition!
@param done_when_finished If set to true, the done () -slot is auto-called when the given command has completed */
	void addRCommand (RCommand *command, bool done_when_finished=false);
signals:
	void cancelled ();
public slots:
/** needed internally so we can easily keep track of whether the dialog is alive or not */
	void dialogDestroyed ();
/** the corresponding action has finished. If there have been no errors, the dialog is also closed. Otherwise, the text of the "cancel" button is changed to "finished". */
	void done ();
	void newError (const QString &error);
/** usually you will call newError instead. However, if in case of an error, you also want to show the regular output, use this function to add output. The output is added to the internal error_log, but the dialog is not shown until you call newError (). */
	void newOutput (const QString &output);
private:
	void createDialog ();

	RKProgressControlDialog *dialog;
	QValueList<ROutput> output_log;

	RCommand *done_command;

	bool autodelete;
	bool modal;
	bool is_done;
	int mode;
	QString text;
	QString caption;
protected:
	void newOutput (RCommand *, ROutput *output);
	void rCommandDone (RCommand *command);
};

/** This class provides the dialog shown as part of an RKProgressControl. Generally you should not use this class directly, but rather use RKProgressControl. */
class RKProgressControlDialog : public QDialog {
	Q_OBJECT
public:
/** constructor. */
	RKProgressControlDialog (const QString &text, const QString &caption, int mode_flags, bool modal);
/** destructor. */
	~RKProgressControlDialog ();
public:
	void addOutput (const ROutput *output);
	void setCloseTextToClose ();
	void done ();
public slots:
	void toggleOutputButtonPressed ();
protected:
	void closeEvent (QCloseEvent *e);
private:
	QLabel *output_caption;
	QLabel *error_indicator;
	QTextEdit *output_text;
	QVBox *output_box;

	QString show_output_text;
	QString hide_output_text;

	QPushButton *close_button;
	QPushButton *toggle_output_button;

	bool prevent_close;
	bool is_done;
};

#endif

Index: Makefile.am
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/misc/Makefile.am,v
retrieving revision 1.11
retrieving revision 1.12
diff -C2 -d -r1.11 -r1.12
*** Makefile.am	5 Apr 2006 20:26:08 -0000	1.11
--- Makefile.am	10 Sep 2006 20:12:21 -0000	1.12
***************
*** 4,10 ****
  libmisc_a_SOURCES = rkerrordialog.cpp rkspinbox.cpp \
  			getfilenamewidget.cpp rkobjectlistview.cpp rkcanceldialog.cpp xmlhelper.cpp \
! 	multistringselector.cpp rkcommonfunctions.cpp
  noinst_HEADERS = rkerrordialog.h rkspinbox.h getfilenamewidget.h \
  	rkobjectlistview.h rkcanceldialog.h xmlhelper.h multistringselector.h \
! 	rkcommonfunctions.h
  
--- 4,10 ----
  libmisc_a_SOURCES = rkerrordialog.cpp rkspinbox.cpp \
  			getfilenamewidget.cpp rkobjectlistview.cpp rkcanceldialog.cpp xmlhelper.cpp \
! 	multistringselector.cpp rkcommonfunctions.cpp rkprogresscontrol.cpp
  noinst_HEADERS = rkerrordialog.h rkspinbox.h getfilenamewidget.h \
  	rkobjectlistview.h rkcanceldialog.h xmlhelper.h multistringselector.h \
! 	rkcommonfunctions.h rkprogresscontrol.h
  

--- NEW FILE: rkprogresscontrol.cpp ---
/***************************************************************************
                          rkprogresscontol  -  description
                             -------------------
    begin                : Sun Sep 10 2006
    copyright            : (C) 2006 by Thomas Friedrichsmeier
    email                : tfry at users.sourceforge.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "rkprogresscontrol.h"

#include <klocale.h>

#include "../rkglobals.h"
#include "../rbackend/rinterface.h"

#include "../debug.h"

RKProgressControl::RKProgressControl (QObject *parent, const QString &text, const QString &caption, int mode_flags) : QObject (parent) {
	RK_TRACE (MISC);

	RKProgressControl::text = text;
	RKProgressControl::caption = caption;
	RKProgressControl::mode = mode_flags;

	dialog = 0;
	is_done = false;
	modal = false;
	autodelete = false;
	done_command = 0;
}

RKProgressControl::~RKProgressControl () {
	RK_TRACE (MISC);

	if (!is_done) done ();
}

bool RKProgressControl::doModal (bool autodelete) {
	RK_TRACE (MISC);
	RK_ASSERT (!dialog);

	modal = true;
	createDialog ();

	int res = dialog->exec ();
	RK_ASSERT ((res == QDialog::Accepted) || (res == QDialog::Rejected));

	bool ret = is_done;		// for good style, we copy this onto the stack, as we are about to self destruct
	if (autodelete) deleteLater ();

	return ret;
}

void RKProgressControl::doNonModal (bool autodelete) {
	RK_TRACE (MISC);
	RK_ASSERT (!dialog);

	RKProgressControl::autodelete = autodelete;
	if ((!dialog) && (mode & ShowAtOnce)) {		// actually, dialog should alway be 0 at this point
		createDialog ();
	}
}

void RKProgressControl::newError (const QString &error) {
	RK_TRACE (MISC);

	if (!(mode & IncludeErrorOutput)) return;

	ROutput outputc;
	outputc.type = ROutput::Error;
	outputc.output = error;

	output_log.append (outputc);

	if (mode & RaiseOnError) {
		if (!dialog) createDialog ();
		dialog->raise ();
	}
	if (dialog) dialog->addOutput (&outputc);
}

void RKProgressControl::newOutput (const QString &output) {
	RK_TRACE (MISC);

	if (!(mode & IncludeRegularOutput)) return;

	ROutput outputc;
	outputc.type = ROutput::Output;
	outputc.output = output;

	output_log.append (outputc);

	if (mode & RaiseOnRegularOutput) {
		if (!dialog) createDialog ();
		dialog->raise ();
	}
	if (dialog) dialog->addOutput (&outputc);
}

void RKProgressControl::resetOutput () {
	RK_TRACE (MISC);

	output_log.clear ();
}

void RKProgressControl::addRCommand (RCommand *command, bool done_when_finished) {
	RK_TRACE (MISC);
	RK_ASSERT (command);

	command->addReceiver (this);
	if (done_when_finished) done_command = command;
}

void RKProgressControl::dialogDestroyed () {
	RK_TRACE (MISC);

	dialog = 0;
	if ((!is_done) && (mode & AllowCancel)) {
		is_done = true;
		if (mode & AutoCancelCommands) {
			for (RCommandList::const_iterator it = outstanding_commands.begin (); it != outstanding_commands.end (); ++it) {
				RKGlobals::rInterface ()->cancelCommand (*it);
			}
		}
		emit (cancelled ());
	}
}

void RKProgressControl::done () {
	RK_TRACE (MISC);

	is_done = true;
	if (dialog) {
		dialog->setCloseTextToClose ();
		dialog->done ();
	}

	if ((!modal) && autodelete) {
		if (dialog) disconnect (dialog, SIGNAL (destroyed ()), this, SLOT (dialogDestroyed ()));		// we're already dead
		deleteLater ();
	}
}

void RKProgressControl::createDialog () {
	RK_TRACE (MISC);

	dialog = new RKProgressControlDialog (text, caption, mode, modal);
	connect (dialog, SIGNAL (destroyed ()), this, SLOT (dialogDestroyed ()));
	if (is_done) done ();
	for (QValueList<ROutput>::const_iterator it = output_log.begin (); it != output_log.end (); ++it) {
		dialog->addOutput (&(*it));
	}
}

void RKProgressControl::newOutput (RCommand *, ROutput *output) {
	RK_TRACE (MISC);
	RK_ASSERT (output);

	if (output->type == ROutput::Output) {
		newOutput (output->output);
	} else {
		newError (output->output);
	}
}

void RKProgressControl::rCommandDone (RCommand * command) {
	RK_TRACE (MISC);

	if (command == done_command) done ();
}



//////////////////////////// RKProgressControlDialog ///////////////////////////////////////////7

#include <qlayout.h>
#include <qtextedit.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <qvbox.h>

RKProgressControlDialog::RKProgressControlDialog (const QString &text, const QString &caption, int mode_flags, bool modal) : QDialog (0, 0, modal, Qt::WDestructiveClose) {
	RK_TRACE (MISC);

	setCaption (caption);

	QVBoxLayout *vbox = new QVBoxLayout (this, RKGlobals::marginHint (), RKGlobals::spacingHint ());

	QLabel *label = new QLabel (text, this);
	label->setAlignment (Qt::AlignAuto | Qt::ExpandTabs | Qt::WordBreak);
	vbox->addWidget (label);

	error_indicator = new QLabel (i18n ("<b>There have been errors and / or warnings! See below for a transcript</b>"), this);
	error_indicator->setPaletteForegroundColor (QColor (255, 0, 0));
	error_indicator->hide ();
	vbox->addWidget (error_indicator);

	output_box = new QVBox (this);
	vbox->addWidget (output_box);
	if (mode_flags & (RKProgressControl::IncludeErrorOutput | RKProgressControl::IncludeRegularOutput)) {
		QString ocaption;
		if (mode_flags & RKProgressControl::IncludeRegularOutput) {
			show_output_text = i18n ("Show Output");
			hide_output_text = i18n ("Hide Output");
			ocaption = i18n ("Output:");
		} else {
			show_output_text = i18n ("Show Errors / Warnings");
			hide_output_text = i18n ("Hide Errors / Warnings");
			ocaption = i18n ("Errors / Warnings:");
		}
		output_caption = new QLabel (ocaption, output_box);

		output_text = new QTextEdit (output_box);
		output_text->setReadOnly (true);
		output_text->setTextFormat (PlainText);
		output_text->setUndoRedoEnabled (false);

		if (!(mode_flags & RKProgressControl::OutputShownByDefault)) {
			output_box->hide ();
		}
	}

	QHBoxLayout *button_layout = new QHBoxLayout (0, 0, RKGlobals::spacingHint ());
	vbox->addLayout (button_layout);

	toggle_output_button = new QPushButton (show_output_text, this);
	if (!(mode_flags & RKProgressControl::OutputSwitchable)) toggle_output_button->hide ();
	if (mode_flags & RKProgressControl::OutputShownByDefault) toggle_output_button->setText (hide_output_text);
	connect (toggle_output_button, SIGNAL (clicked ()), this, SLOT (toggleOutputButtonPressed ()));
	button_layout->addWidget (toggle_output_button);
	button_layout->addStretch ();

	close_button = new QPushButton (QString::null, this);
	if (mode_flags & RKProgressControl::AllowCancel) close_button->setText (i18n ("Cancel"));
	else setCloseTextToClose ();
	connect (close_button, SIGNAL (clicked ()), this, SLOT (reject ()));
	button_layout->addWidget (close_button);

	prevent_close = (mode_flags & RKProgressControl::PreventClose);
	is_done = false;
}

RKProgressControlDialog::~RKProgressControlDialog () {
	RK_TRACE (MISC);
}

void RKProgressControlDialog::addOutput (const ROutput *output) {
	RK_TRACE (MISC);

	if (output->type != ROutput::Output) {
		output_text->setColor (Qt::red);
		if (!output_box->isShown ()) toggleOutputButtonPressed ();
		error_indicator->show ();
	}

	output_text->append (output->output);
	output_text->setColor (Qt::black);
}

void RKProgressControlDialog::setCloseTextToClose () {
	RK_TRACE (MISC);

	close_button->setText (i18n ("Done"));
}

void RKProgressControlDialog::toggleOutputButtonPressed () {
	RK_TRACE (MISC);

	if (output_box->isShown ()) {
		output_box->hide ();
		toggle_output_button->setText (show_output_text);
	} else {
		output_box->show ();
		toggle_output_button->setText (hide_output_text);
	}
}

void RKProgressControlDialog::done () {
	RK_TRACE (MISC);

	is_done = true;
	if (!output_box->isShown ()) reject ();
}

void RKProgressControlDialog::closeEvent (QCloseEvent *e) {
	RK_TRACE (DIALOGS);

	if (prevent_close && (!is_done)) {
		e->ignore ();
	} else {
		QDialog::closeEvent (e);
	}
}

#include "rkprogresscontrol.moc"





More information about the rkward-tracker mailing list