pqEventDispatcher.cxx 8.08 KB
Newer Older
1 2 3 4 5
/*=========================================================================

   Program: ParaView
   Module:    pqEventDispatcher.cxx

6
   Copyright (c) 2005-2008 Sandia Corporation, Kitware Inc.
7 8 9
   All rights reserved.

   ParaView is a free software; you can redistribute it and/or modify it
10
   under the terms of the ParaView license version 1.2. 
11

12
   See License_v1.2.txt for the full ParaView license.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
   A copy of this license can be obtained by contacting
   Kitware Inc.
   28 Corporate Drive
   Clifton Park, NY 12065
   USA

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/

33 34
#include "pqEventDispatcher.h"

35 36 37 38 39
#include "pqEventPlayer.h"
#include "pqEventSource.h"

#include <QAbstractEventDispatcher>
#include <QtDebug>
40
#include <QApplication>
41
#include <QEventLoop>
42
#include <QThread>
43 44
#include <QDialog>
#include <QMainWindow>
45

46 47
#include <iostream>
using namespace std;
48

49
bool pqEventDispatcher::DeferMenuTimeouts = false;
50 51 52
//-----------------------------------------------------------------------------
pqEventDispatcher::pqEventDispatcher(QObject* parentObject) :
  Superclass(parentObject)
53
{
54 55 56 57
  this->ActiveSource = NULL;
  this->ActivePlayer = NULL;
  this->PlayBackStatus = false;
  this->PlayBackFinished = false;
58

59 60 61
#ifdef __APPLE__
  this->BlockTimer.setInterval(1000);
#else
62
  this->BlockTimer.setInterval(100);
63
#endif
64 65 66
  this->BlockTimer.setSingleShot(true);
  QObject::connect(&this->BlockTimer, SIGNAL(timeout()),
                   this, SLOT(playEventOnBlocking()));
67 68
}

69
//-----------------------------------------------------------------------------
70 71 72 73
pqEventDispatcher::~pqEventDispatcher()
{
}

74 75 76
//-----------------------------------------------------------------------------
void pqEventDispatcher::aboutToBlock()
{
77
  // if (!pqEventDispatcher::DeferMenuTimeouts)
78 79 80
    {
    if (!this->BlockTimer.isActive())
      {
81
      // cout << "aboutToBlock" << endl;
82 83 84 85 86 87 88 89 90
      // Request a delayed playback for an event.
      this->BlockTimer.start();
      }
    }
}

//-----------------------------------------------------------------------------
void pqEventDispatcher::awake()
{
91 92 93 94 95
  //if (!pqEventDispatcher::DeferMenuTimeouts)
  //  {
  //  // cout << "awake" << endl;
  //  // this->BlockTimer.stop();
  //  }
96 97
}

98
//-----------------------------------------------------------------------------
99
bool pqEventDispatcher::playEvents(pqEventSource& source, pqEventPlayer& player)
100
{
101
  if (this->ActiveSource || this->ActivePlayer)
102 103
    {
    qCritical() << "Event dispatcher is already playing";
104
    return false;
105 106
    }

107 108 109
  this->ActiveSource = &source;
  this->ActivePlayer = &player;

110
  QApplication::setEffectEnabled(Qt::UI_General, false);
111

112 113 114 115 116 117
  QObject::connect(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()),
                   this, SLOT(aboutToBlock()));
  QObject::connect(QAbstractEventDispatcher::instance(), SIGNAL(awake()),
                   this, SLOT(awake()));


118 119 120 121 122 123 124 125 126 127 128
  // This is how the playback logic works:
  // * In here, we continuously keep on playing one event after another until
  //   we are done processing all the events.
  // * If a modal dialog pops up, then this->aboutToBlock() gets called. To me
  //   accurate, aboutToBlock() is called everytime the sub-event loop is entered
  //   and more modal dialogs that loop is entered after processing of each event
  //   (not merely when the dialog pops up).
  // * In this->aboutToBlock() we start a timer which on timeout processes just 1 event.
  // * After executing that event, if the dialog still is up, them aboutToBlock() will
  //   be called again and the cycle continues. If not, the control returns to this main
  //   playback loop, and it continues.
129 130
  this->PlayBackStatus = true; // success.
  this->PlayBackFinished = false;
131 132 133 134
  while (!this->PlayBackFinished)
    {
    this->playEvent();
    }
135 136
  this->ActiveSource = NULL;
  this->ActivePlayer = NULL;
137 138 139 140 141 142

  QObject::disconnect(QAbstractEventDispatcher::instance(), SIGNAL(aboutToBlock()),
                   this, SLOT(aboutToBlock()));
  QObject::disconnect(QAbstractEventDispatcher::instance(), SIGNAL(awake()),
                   this, SLOT(awake()));

143
  return this->PlayBackStatus;
144
}
145

146
//-----------------------------------------------------------------------------
147
void pqEventDispatcher::playEventOnBlocking()
148
{
149 150 151 152 153 154
  if (pqEventDispatcher::DeferMenuTimeouts)
    {
    this->BlockTimer.start();
    return;
    }

155 156
  //cout << "---blocked event: " << endl;
  // if needed for debugging, I can print blocking annotation here.
157
  this->playEvent(1);
158

159 160 161 162
  //if (!this->BlockTimer.isActive())
  //  {
  //  this->BlockTimer.start();
  //  }
163
}
164

165
//-----------------------------------------------------------------------------
166
void pqEventDispatcher::playEvent(int indent)
167 168
{
  this->BlockTimer.stop();
169
  if (this->PlayBackFinished)
170
    {
171
    return;
172
    }
173

174
  if (!this->ActiveSource)
175
    {
176 177 178
    this->PlayBackFinished = true;
    this->PlayBackStatus = false; // failure.
    qCritical("Internal error: playEvent called without a valid event source.");
179 180 181
    return;
    }

182 183 184
  QString object;
  QString command;
  QString arguments;
185
  
186 187
  int result = this->ActiveSource->getNextEvent(object, command, arguments);
  if (result == pqEventSource::DONE)
188
    {
189
    this->PlayBackFinished = true;
190 191
    return;
    }
192 193
  else if(result == pqEventSource::FAILURE)
    {
194 195
    this->PlayBackFinished = true;
    this->PlayBackStatus = false; // failure.
196 197
    return;
    }
198
    
199 200 201 202 203
  QApplication::syncX();
  static unsigned long counter=0;
  unsigned long local_counter = counter++;
  QString pretty_name = object.mid(object.lastIndexOf('/'));
  bool print_debug = getenv("PV_DEBUG_TEST") != NULL;
204
#if defined(WIN32) || defined(__APPLE__) // temporary debugging on both platforms.
205 206
  print_debug = true;
#endif
207 208
  if (print_debug)
    {
209 210
    cout <<  QTime::currentTime().toString("hh:mm:ss").toStdString().c_str()
         << " : "
211 212 213 214 215
         << QString().fill(' ', 4*indent).toStdString().c_str()
         << local_counter << ": Test (" << indent << "): "
         << pretty_name.toStdString().c_str() << ": "
         << command.toStdString().c_str() << " : "
         << arguments.toStdString().c_str() << endl;
216 217
    }

218
  bool error = false;
219
  this->ActivePlayer->playEvent(object, command, arguments, error);
220
  this->BlockTimer.stop();
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
221 222
  //QCoreApplication::sendPostedEvents();
  //QCoreApplication::flush();
223 224 225 226 227 228 229 230 231 232
  if (print_debug)
    {
    cout << "       -- pre-processEventsAndWait: " << local_counter <<endl;
    }
  // let what's going to happen after the playback, happen.
  this->processEventsAndWait(QT_TESTING_EVENT_PLAYBACK_DELAY);
  if (print_debug)
    {
    cout << "       -- post-processEventsAndWait: " << local_counter <<endl;
    }
233
  this->BlockTimer.stop();
234 235
  if (print_debug)
    {
236 237
    cout << QTime::currentTime().toString("hh:mm:ss").toStdString().c_str()
         << " : "
238 239
         << QString().fill(' ', 4*indent).toStdString().c_str()
         << local_counter << ": Done" << endl;
240 241 242 243 244 245 246
    }
  if (error)
    {
    this->PlayBackStatus  = false;
    this->PlayBackFinished = true;
    return;
    }
247 248
}

249
//-----------------------------------------------------------------------------
250
void pqEventDispatcher::processEventsAndWait(int ms)
251
{
252 253
  bool prev = pqEventDispatcher::DeferMenuTimeouts;
  pqEventDispatcher::DeferMenuTimeouts = true;
254 255
  if (ms > 0)
    {
256
    QApplication::processEvents();
257 258
    QEventLoop loop;
    QTimer::singleShot(ms, &loop, SLOT(quit()));
259
    loop.exec();
260
    }
261
  QApplication::processEvents();
262
  pqEventDispatcher::DeferMenuTimeouts = prev;
263
}