~ubuntu-branches/ubuntu/maverick/freecad/maverick

« back to all changes in this revision

Viewing changes to src/Gui/ProgressDialog.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Teemu Ikonen
  • Date: 2009-07-16 18:37:41 UTC
  • Revision ID: james.westby@ubuntu.com-20090716183741-oww9kcxqrk991i1n
Tags: upstream-0.8.2237
ImportĀ upstreamĀ versionĀ 0.8.2237

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright (c) 2009 Werner Mayer <wmayer@users.sourceforge.net>        *
 
3
 *                                                                         *
 
4
 *   This file is part of the FreeCAD CAx development system.              *
 
5
 *                                                                         *
 
6
 *   This library is free software; you can redistribute it and/or         *
 
7
 *   modify it under the terms of the GNU Library General Public           *
 
8
 *   License as published by the Free Software Foundation; either          *
 
9
 *   version 2 of the License, or (at your option) any later version.      *
 
10
 *                                                                         *
 
11
 *   This library  is distributed in the hope that it will be useful,      *
 
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
14
 *   GNU Library General Public License for more details.                  *
 
15
 *                                                                         *
 
16
 *   You should have received a copy of the GNU Library General Public     *
 
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
 
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 
20
 *                                                                         *
 
21
 ***************************************************************************/
 
22
 
 
23
 
 
24
#include "PreCompiled.h"
 
25
 
 
26
#include "ProgressDialog.h"
 
27
#include "MainWindow.h"
 
28
 
 
29
 
 
30
using namespace Gui;
 
31
 
 
32
 
 
33
namespace Gui {
 
34
struct SequencerDialogPrivate
 
35
{
 
36
    ProgressDialog* dlg;
 
37
    QTime measureTime;
 
38
    QTime progressTime;
 
39
    QString text;
 
40
    bool guiThread;
 
41
};
 
42
}
 
43
 
 
44
 
 
45
SequencerDialog* SequencerDialog::_pclSingleton = 0;
 
46
 
 
47
SequencerDialog* SequencerDialog::instance()
 
48
{
 
49
    // not initialized?
 
50
    if (!_pclSingleton)
 
51
        _pclSingleton = new SequencerDialog();
 
52
    return _pclSingleton;
 
53
}
 
54
 
 
55
SequencerDialog::SequencerDialog ()
 
56
{
 
57
    d = new SequencerDialogPrivate;
 
58
    d->dlg = new ProgressDialog(this,getMainWindow());
 
59
    d->guiThread = true;
 
60
}
 
61
 
 
62
SequencerDialog::~SequencerDialog()
 
63
{
 
64
    delete d;
 
65
}
 
66
 
 
67
void SequencerDialog::pause()
 
68
{
 
69
    QThread *currentThread = QThread::currentThread();
 
70
    QThread *thr = d->dlg->thread(); // this is the main thread
 
71
    if (thr == currentThread)
 
72
        // allow key handling of dialog
 
73
        d->dlg->leaveControlEvents();
 
74
}
 
75
 
 
76
void SequencerDialog::resume()
 
77
{
 
78
    QThread *currentThread = QThread::currentThread();
 
79
    QThread *thr = d->dlg->thread(); // this is the main thread
 
80
    if (thr == currentThread)
 
81
        d->dlg->enterControlEvents(); // grab again
 
82
}
 
83
 
 
84
void SequencerDialog::startStep()
 
85
{
 
86
    QThread *currentThread = QThread::currentThread();
 
87
    QThread *thr = d->dlg->thread(); // this is the main thread
 
88
    if (thr != currentThread) {
 
89
        d->guiThread = false;
 
90
        d->dlg->setRange(0, (int)nTotalSteps);
 
91
        d->dlg->setModal(false);
 
92
        if (nTotalSteps == 0) {
 
93
            d->progressTime.start();
 
94
        }
 
95
 
 
96
        d->measureTime.start();
 
97
        QMetaObject::invokeMethod(d->dlg, "setValue", Qt::QueuedConnection,
 
98
            QGenericReturnArgument(), Q_ARG(int,0));
 
99
    }
 
100
    else {
 
101
        d->guiThread = true;
 
102
        d->dlg->setRange(0, (int)nTotalSteps);
 
103
        d->dlg->setModal(true);
 
104
        if (nTotalSteps == 0) {
 
105
            d->progressTime.start();
 
106
        }
 
107
 
 
108
        d->measureTime.start();
 
109
        d->dlg->setValue(0);
 
110
        d->dlg->enterControlEvents();
 
111
    }
 
112
}
 
113
 
 
114
void SequencerDialog::nextStep(bool canAbort)
 
115
{
 
116
    QThread *currentThread = QThread::currentThread();
 
117
    QThread *thr = d->dlg->thread(); // this is the main thread
 
118
    if (thr != currentThread) {
 
119
        setProgress((int)nProgress+1);
 
120
    }
 
121
    else {
 
122
        if (wasCanceled() && canAbort) {
 
123
            // restore cursor
 
124
            pause();
 
125
            bool ok = d->dlg->canAbort();
 
126
            // continue and show up wait cursor if needed
 
127
            resume();
 
128
 
 
129
            // force to abort the operation
 
130
            if ( ok ) {
 
131
                abort();
 
132
            } else {
 
133
                rejectCancel();
 
134
                setProgress((int)nProgress+1);
 
135
            }
 
136
        }
 
137
        else {
 
138
            setProgress((int)nProgress+1);
 
139
        }
 
140
    }
 
141
}
 
142
 
 
143
void SequencerDialog::setProgress(int step)
 
144
{
 
145
    QThread *currentThread = QThread::currentThread();
 
146
    QThread *thr = d->dlg->thread(); // this is the main thread
 
147
    // if number of total steps is unknown then increment only by one
 
148
    if (nTotalSteps == 0) {
 
149
        int elapsed = d->progressTime.elapsed();
 
150
        // allow an update every 500 milliseconds only
 
151
        if (elapsed > 500) {
 
152
            d->progressTime.restart();
 
153
            if (thr != currentThread) {
 
154
                QMetaObject::invokeMethod(d->dlg, "setValue", Qt::/*Blocking*/QueuedConnection,
 
155
                    QGenericReturnArgument(), Q_ARG(int,d->dlg->value()+1));
 
156
            }
 
157
            else {
 
158
                d->dlg->setValue(d->dlg->value()+1);
 
159
                qApp->processEvents();
 
160
            }
 
161
        }
 
162
    }
 
163
    else {
 
164
        if (thr != currentThread) {
 
165
            QMetaObject::invokeMethod(d->dlg, "setValue", Qt::/*Blocking*/QueuedConnection,
 
166
                QGenericReturnArgument(), Q_ARG(int,step));
 
167
            if (d->dlg->isVisible())
 
168
                showRemainingTime();
 
169
        }
 
170
        else {
 
171
            d->dlg->setValue(step);
 
172
            if (d->dlg->isVisible())
 
173
                showRemainingTime();
 
174
            qApp->processEvents();
 
175
        }
 
176
    }
 
177
}
 
178
 
 
179
void SequencerDialog::showRemainingTime()
 
180
{
 
181
    QThread *currentThread = QThread::currentThread();
 
182
    QThread *thr = d->dlg->thread(); // this is the main thread
 
183
 
 
184
    int elapsed = d->measureTime.elapsed();
 
185
    int progress = d->dlg->value();
 
186
    int totalSteps = d->dlg->maximum() - d->dlg->minimum();
 
187
 
 
188
    QString txt = d->text;
 
189
    // More than 5 percent complete or more than 5 secs have elapsed.
 
190
    if (progress * 20 > totalSteps || elapsed > 5000) {
 
191
        int rest = (int) ( (double) totalSteps/progress * elapsed ) - elapsed;
 
192
 
 
193
        // more than 1 secs have elapsed and at least 100 ms are remaining
 
194
        if (elapsed > 1000 && rest > 100) {
 
195
            QTime time( 0,0, 0);
 
196
            time = time.addSecs( rest/1000 );
 
197
            QString remain = Gui::ProgressDialog::tr("Remaining: %1").arg(time.toString());
 
198
            QString status = QString::fromAscii("%1\t[%2]").arg(txt).arg(remain);
 
199
 
 
200
            if (thr != currentThread) {
 
201
                QMetaObject::invokeMethod(d->dlg, "setLabelText",
 
202
                    Qt::/*Blocking*/QueuedConnection,
 
203
                    QGenericReturnArgument(),
 
204
                    Q_ARG(QString,status));
 
205
            }
 
206
            else {
 
207
                d->dlg->setLabelText(status);
 
208
            }
 
209
        }
 
210
    }
 
211
}
 
212
 
 
213
void SequencerDialog::resetData()
 
214
{
 
215
    QThread *currentThread = QThread::currentThread();
 
216
    QThread *thr = d->dlg->thread(); // this is the main thread
 
217
    if (thr != currentThread) {
 
218
        QMetaObject::invokeMethod(d->dlg, "reset", Qt::QueuedConnection);
 
219
        QMetaObject::invokeMethod(d->dlg, "hide", Qt::QueuedConnection);
 
220
        QMetaObject::invokeMethod(d->dlg, "setLabelText",
 
221
            Qt::/*Blocking*/QueuedConnection,
 
222
            QGenericReturnArgument(),
 
223
            Q_ARG(QString,QString()));
 
224
    }
 
225
    else {
 
226
        d->dlg->reset();
 
227
        // Note: Under Qt 4.1.4 this forces to run QWindowsStyle::eventFilter() twice 
 
228
        // handling the same event thus a warning is printed. Possibly, this is a bug
 
229
        // in Qt. The message is QEventDispatcherUNIX::unregisterTimer: invalid argument.
 
230
        d->dlg->hide();
 
231
        d->dlg->setLabelText(QString());
 
232
        d->dlg->leaveControlEvents();
 
233
    }
 
234
 
 
235
    SequencerBase::resetData();
 
236
}
 
237
 
 
238
void SequencerDialog::abort()
 
239
{
 
240
    //resets
 
241
    resetData();
 
242
    Base::AbortException exc("Aborting...");
 
243
    throw exc;
 
244
}
 
245
 
 
246
void SequencerDialog::setText (const char* pszTxt)
 
247
{
 
248
    QThread *currentThread = QThread::currentThread();
 
249
    QThread *thr = d->dlg->thread(); // this is the main thread
 
250
 
 
251
    // set label text of the dialog
 
252
    d->text = pszTxt ? QString::fromUtf8(pszTxt) : QLatin1String("");
 
253
    if (thr != currentThread) {
 
254
        QMetaObject::invokeMethod(d->dlg, "setLabelText",
 
255
            Qt::/*Blocking*/QueuedConnection,
 
256
            QGenericReturnArgument(),
 
257
            Q_ARG(QString,d->text));
 
258
    }
 
259
    else {
 
260
        d->dlg->setLabelText(d->text);
 
261
    }
 
262
}
 
263
 
 
264
bool SequencerDialog::isBlocking() const
 
265
{
 
266
    return d->guiThread;
 
267
}
 
268
 
 
269
// -------------------------------------------------------
 
270
 
 
271
/* TRANSLATOR Gui::ProgressDialog */
 
272
 
 
273
ProgressDialog::ProgressDialog (SequencerDialog* s, QWidget * parent)
 
274
    : QProgressDialog(parent, Qt::FramelessWindowHint), sequencer(s)
 
275
{
 
276
    connect(this, SIGNAL(canceled()), this, SLOT(onCancel()));
 
277
}
 
278
 
 
279
ProgressDialog::~ProgressDialog ()
 
280
{
 
281
}
 
282
 
 
283
void ProgressDialog::onCancel()
 
284
{
 
285
    sequencer->tryToCancel();
 
286
}
 
287
 
 
288
bool ProgressDialog::canAbort() const
 
289
{
 
290
    int ret = QMessageBox::question(getMainWindow(),tr("Aborting"),
 
291
    tr("Do you really want to abort the operation?"),  QMessageBox::Yes, 
 
292
    QMessageBox::No|QMessageBox::Default);
 
293
 
 
294
    return (ret == QMessageBox::Yes) ? true : false;
 
295
}
 
296
 
 
297
void ProgressDialog::enterControlEvents()
 
298
{
 
299
    qApp->installEventFilter(this);
 
300
 
 
301
    // Make sure that we get the key events, otherwise the Inventor viewer usurps the key events
 
302
    // This also disables accelerators.
 
303
    grabKeyboard();
 
304
}
 
305
 
 
306
void ProgressDialog::leaveControlEvents()
 
307
{
 
308
    qApp->removeEventFilter(this);
 
309
 
 
310
    // relase the keyboard again
 
311
    releaseKeyboard();
 
312
}
 
313
 
 
314
bool ProgressDialog::eventFilter(QObject* o, QEvent* e)
 
315
{
 
316
    if (sequencer->isRunning() && e != 0) {
 
317
        switch ( e->type() )
 
318
        {
 
319
        // check for ESC
 
320
        case QEvent::KeyPress:
 
321
            {
 
322
                QKeyEvent* ke = (QKeyEvent*)e;
 
323
                if (ke->key() == Qt::Key_Escape) {
 
324
                    // cancel the operation
 
325
                    this->cancel();
 
326
                }
 
327
 
 
328
                return true;
 
329
            }   break;
 
330
 
 
331
        // ignore all these events
 
332
        case QEvent::KeyRelease:
 
333
        case QEvent::Enter:
 
334
        case QEvent::Leave:
 
335
        case QEvent::MouseButtonDblClick:
 
336
        case QEvent::ContextMenu:
 
337
            {
 
338
                return true;
 
339
            }   break;
 
340
      
 
341
        // special case if the main window's close button was pressed 
 
342
        case QEvent::Close:
 
343
            {
 
344
                // avoid to exit while app is working
 
345
                // note: all other widget types are allowed to be closed anyway
 
346
                if (o == getMainWindow()) {
 
347
                    e->ignore();
 
348
                    return true; 
 
349
                }
 
350
            }   break;
 
351
 
 
352
        // do a system beep and ignore the event
 
353
        case QEvent::MouseButtonPress:
 
354
            {
 
355
                QApplication::beep();
 
356
                return true;
 
357
            }   break;
 
358
 
 
359
        default:
 
360
            {
 
361
            }   break;
 
362
        }
 
363
    }
 
364
 
 
365
    return QProgressDialog::eventFilter(o, e);
 
366
}
 
367
 
 
368
#include "moc_ProgressDialog.cpp"