00001 // Progress - a wrapper around QProgressDialog 00002 // Copyright (C) 2000-2003 bozo & sgbeal @users.sourceforge.net 00003 // 00004 // This program is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU General Public License 00006 // as published by the Free Software Foundation; either version 2 00007 // of the License, or (at your option) any later version. 00008 // 00009 // This program is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License 00015 // along with this program; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 00018 #ifndef _FUN_PROGRESS_H 00019 #define _FUN_PROGRESS_H 00020 00021 #include <fun/fun.h> 00022 #include <sys/time.h> // for timeval 00023 00024 namespace fun { 00025 00026 /** 00027 * This is a wrapper around QProgressDialog for classes which want to report 00028 * progress information, but don't want to know whether there's a QApplication 00029 * which needs to have processEvents() called, or whether other chunks of code 00030 * already have a progress dialog up, etc. 00031 * 00032 * If there are places where you notice multiple progress dialogs popping 00033 * up in series, you can fix that by nesting them in an outer start()/finish() 00034 * pair. For example, when loubetomy loads a map, it performs three steps: 00035 * <OL> 00036 * <LI>creates a SerialTree from the given file. 00037 * <LI>deserializes the HexMap from the resulting SerialTree. 00038 * <LI>gives the resulting HexMap to HexMapView so that the necessary graphic 00039 * bits can be created. 00040 * </OL> 00041 * All of those steps are performed by chunks of library code which don't 00042 * know about each other--and loubetomy doesn't want to know which of them, 00043 * if any, report progress information--so loubetomy calls Progress::start(), 00044 * does the first step, calls Progress::update() (which tells it whether the 00045 * user hit the cancel button while SerialTree was doing its thing), then 00046 * deserializes the HexMap, then calls Progress::update() again (which, 00047 * again, tells it whether the user hit the cancel button while the HexMap 00048 * was deserializing itself), then gives the map to its HexMapView, & finally 00049 * calls Progress::finish() to make the dialog go away (if one was displayed). 00050 * 00051 * (If the library code was responsible for fondling the progress dialog 00052 * itself, it would be more complicated, and either there would be gaps when 00053 * the program was busy but no dialog was up, or there would be points when 00054 * two progress dialogs were up, & in either case it would be messier for 00055 * loubetomy to know whether the user had hit "cancel" in the dialog displayed 00056 * by the library.) 00057 */ 00058 class Progress 00059 { 00060 public: 00061 /** 00062 * Indicates that some operation is starting for which progress will be 00063 * reported. Whether this does anything depends on a couple of things: 00064 * <UL> 00065 * <LI>If no QApplication has been passed to setQApplication(), 00066 * this just notes the start time. (It might not even do that.) 00067 * Keeping this fast for non-interactive programs which don't care 00068 * about popping up progress dialogs is important! 00069 * <LI>Otherwise, if this call is nested inside another start/finish 00070 * pair, then it updates the existing QProgressDialog, if any. 00071 * <LI>Otherwise, this creates a QProgressDialog. (Whether or not the 00072 * dialog shows itself is up to the dialog.) 00073 * </UL> 00074 * 00075 * @param operation A description of the operation being performed. This 00076 * will be displayed in the progress dialog, if any. 00077 * @param steps The number of steps in this operation. 00078 * @param canCancel Whether or not this operation can be cancelled by the 00079 * user. 00080 * 00081 */ 00082 static void start(const QString &operation, int steps, bool canCancel = true); 00083 00084 /** 00085 * Same as start(), so that you don't have to remember whether it's 00086 * "start" or "begin". 00087 */ 00088 static void begin(const QString &operation, int steps, bool canCancel = true) { return start(operation, steps, canCancel); } 00089 00090 /** 00091 * This updates the existing progress dialog, if any. If a progress 00092 * dialog is up, and the user has hit cancel (or if the user hit cancel 00093 * during some nested operation), this returns true; otherwise it returns 00094 * false. 00095 * 00096 * If the user has inidicated that they want to cancel the operation, you 00097 * still need to call finish(). 00098 * 00099 * If no QApplication has been passed to setQApplication(), then update() 00100 * doesn't do anything, and just returns false. 00101 * 00102 * @param step which step has been completed. 00103 */ 00104 static bool update(int step); 00105 00106 /** 00107 * Indicates that the operation is done (even if it's "done" because it 00108 * was cancelled by the user). What this does depends on several things: 00109 * 00110 * <UL> 00111 * <LI>If no QApplication has been passed to setQApplication(), 00112 * this might print the elapsed time, or do nothing. 00113 * <LI>Otherwise, if this call is nested inside another start/finish 00114 * pair, then it restores the existing QProgressDialog with the 00115 * "outer" ("anti-nested"?) operation's values. 00116 * <LI>Otherwise, this cleans up the progress dialog. 00117 * </UL> 00118 */ 00119 static void finish(); 00120 00121 /** 00122 * Same as finish(), so that you don't have to remember whether it's 00123 * "finish" or "end". 00124 */ 00125 static void end() { finish(); } 00126 00127 /** 00128 * Causes the progress dialog, if any, to become hidden. You want to 00129 * do this if you need to pop up a confirmation dialog in the middle of 00130 * some operation; otherwise the progress dialog is probably going to 00131 * be rather rude about popping up in front of the confirmation dialog & 00132 * demanding attention. Regardless of subsequent calls to update(), the 00133 * progress dialog will not be shown again until resume() or finish() is 00134 * called. (In the case of finish(), the dialog won't be shown again 00135 * until the start of the next non-nested operation.) 00136 * 00137 * suspend()/resume() pairs can be nested. Calling suspend() before 00138 * start() has no effect. 00139 */ 00140 static void suspend(); 00141 00142 /** 00143 * Prints a randomly-selected QUB developer's resumé on stdout. 00144 * Err, wait, apparently it causes the progress dialog, if any, to resume 00145 * being shown after a call to suspend(). (It may not actually show 00146 * itself until the next call to update().) 00147 * 00148 * Note that suspend()/resume() calls may be nested; the dialog will not 00149 * actually be displayed until after the outermost resume() call. 00150 */ 00151 static void resume(); 00152 00153 /** 00154 * Returns true if this operation (or a nested one) has been cancelled. 00155 * (The other way to find this out is from the return value from update().) 00156 */ 00157 static bool cancelled(); 00158 00159 /** 00160 * Sets the QApplication whose processEvents() will be called during 00161 * update(). If you create a QApplication, just call this in your 00162 * main() and forget about it. 00163 * 00164 * If this is never called (or is called with a NULL QApplication), the 00165 * other progress methods don't really do anything. 00166 */ 00167 static void setQApplication(QApplication *); 00168 00169 ~Progress(); 00170 00171 private: 00172 Progress(int, const QString &, bool); 00173 00174 int steps; 00175 int step; 00176 bool canCancel; 00177 QString msg; 00178 timeval startTime; 00179 }; 00180 00181 } // namespace fun 00182 00183 #endif // _FUN_PROGRESS_H