1
0
mirror of https://github.com/fwbuilder/fwbuilder synced 2025-06-15 14:47:52 +02:00

Removed tutorial dialog

This commit is contained in:
Roman Bovsunivskiy 2010-02-25 21:04:55 +00:00
parent a91930d5a7
commit a53fd00a45
18 changed files with 122 additions and 915 deletions

View File

@ -0,0 +1,84 @@
Анимация диалога состоит из таких классов:
TutorialDialog
TutorialAnimator
TutorialHelper
MouseBlocker
Каждый из них представлен .cpp и .h файлом, а к TutorialDialog есть еще .ui
файл с интерфейсом.
Что и как делает каждый класс:
TutorialDialog
Это сам интерфейс, в котором демонстрируется html файл с инструкциями. Он
также содержит слайдер для регулировки скорости демонстрации и кнопку
Demonstrate, нажатие на которую запускает анимацию.
Содержимое инструкций заружается из файла :/Tutorial/html/pageN.html
ресурсов программы. Кнопки next и previous активны в зависимости от наличия
файла для следующей/прошлой страницы.
Скорость регулируется от 20 до 70. Это базовое и минимальное значение
скорости в милисекундах, быстрее которого не будет происходить ниодно
действите анимации. Например, симуляция ввода с клавиатуры будет происходить
с паузой в это значение между нажатиями на кнопки.
По нажатию кнопки Demonstrate считывается файл :/Tutorial/commands/pageN.txt
из ресурсов программы, в котором должны находиться инструкции по анимации
действий описаных в html файле, который отображается в данный момент.
Для анимации создается инстанс класс TutorialAnimator с аргументами: ссылкой
на TutorialDialog и текстом файла комманд. Далее запускает его, после чего
управление передается этому классу.
TutorialAnimator
Является наследником QThread, чтобы не блокироваться при открытии модальных
диалогов и меню.
При инициализации первым делом прячет TutorialDialog и разбивает полученый
текст файла команд на строки, каждая из которых является отдельной командой.
Создает инстанс класса TutorialHelper в GUI потоке, через который будет
позже манипулировать интерфейсом.
При запуске блокирует ввод и движения мышки при помощи методов blockInput и
blockMouse из класса TutorialHelper. После чего начинает последовательно
выполнять комманды полученые при инициализации.
В данный момент поддерживаются следующие комманды:
moveMouse X Y
moveMouse objectName1 [objectName2 [... objectNameN]]
clickWidget objectName1 [objectName2 [... objectNameN]]
typeWidget objectName1 [objectName2 [... objectNameN]] text
hoverMenuItem menuName itemName|itemIndex
clickMenuItem menuName itemName|itemIndex
selectComboItem objectName1 [objectName2 [... objectNameN]] itemIndex
selectListItem objectName1 [objectName2 [... objectNameN]] itemIndex
selectTab objectName1 [objectName2 [... objectNameN]] itemIndex
wait SECONDS
moveMouse - переместить указатель мыши в указаную точку или в центр виджета.
clickWidget - переместить указатель мыши в центр виджета и кликнуть.
typeWidget - напечатать текст на клавиатуре когда указаный обьект в фокусе.
hoveMenuItem - переместить указатель мыши на пункт меню.
clickMenuItem - кликнуть пункт меню мышью.
selectComboItem - открыть combo box и выбрать в нем элемент.
selectListItem - выбрать элемент в списке при помощи мыши.
selectTab - выбрать вкладку QTabWidget при помощи мыши
wait - ожидать указаное кол-во секунд.
Для каждой из них есть отдельный метод, который ее обрабатывает.
Все манипуляции с интерфейсом происходят через класс TutorialHelper, который
был создан раньше и выполняется в GUI потоке. Но так как из треда, в котором
TutorialAnimator, вызов метода TutorialHelper приведет к его выполнению не
в GUI-потоке, для вызова этих методов используется QMetaObject::invokeMethod
с аргументом Qt::BlockedQueuedConnection. Это позволяет выполнить метод
когда выполнение программы вернется в основной поток и блокировать
выполнение потока TutorialAnimator пока вызваный метод не выполнится.
Этот класс также содержит такие полезные методы как findChild, findWidget и
getWidget, который наверняка пригодятся также для написания unit-тестов. Они
позволяют рекурсивно искать обьекты по дереву обьектов программы. Для этого
используется поиск в ширину. В отличии от стандартной функции findChild, эти
методы умеют искать не просто первый обьект с указаным именем, а последний
обьект в цепочке наследования.
Например, комманда clickWidget MainWindow SomeWidget TargetButton означает:
найти виджет MainWindow, в нем SomeWidget, в нем TargetButton и кликнуть ее.
Также поддерживается поиск по имени класса: w#className. Например6
moveMouse w#FWWindow objectTreeView - найти обьект класса FWWindow, в
котором найти objectTreeView и переместить курсор мыши в его центр.
TutorialHelper
Этот класс содержит все методы по манипулированию интерфейсом. Его методы
вызываются из TutorialAnimator, но должны выполняться в GUI потоке.
Он также содержит методы blockInput для блокировки ввода и blockMouse для
блокировки движения мыши, которые могут выполняться с любого потока.
MouseBlocker
Наследник QThread, который когда запущен каждые 10 милисекунд перемещает
указатель мыши в его текущее положение. Это полностью блокирует перемещение
мыши пользователем. Используется через TutorialHelper::blockMouse.

View File

@ -292,18 +292,13 @@
<file>Images/fwbuilder3-128x128.png</file>
<file>Images/fwbuilder3.png</file>
<file>Tutorial/html/page0.html</file>
<file>Tutorial/commands/page0.txt</file>
<file>Tutorial/images/0.png</file>
<file>Tutorial/images/1.png</file>
<file>Tutorial/images/2.png</file>
<file>Tutorial/images/3.png</file>
<file>Tutorial/images/new_button.png</file>
<file>Tutorial/html/page1.html</file>
<file>Tutorial/commands/page1.txt</file>
<file>Tutorial/controls.txt</file>
<file>Tutorial/html/page2.html</file>
<file>Tutorial/html/page3.html</file>
<file>Tutorial/commands/page2.txt</file>
<file>Tutorial/commands/page3.txt</file>
</qresource>
</RCC>

View File

@ -1,24 +0,0 @@
#include "MouseBlocker.h"
#include <QCursor>
#include <QTest>
MouseBlocker::MouseBlocker(QObject *parent) :
QThread(parent)
{
this->alive = true;
}
void MouseBlocker::run()
{
while (this->alive)
{
QCursor::setPos(QCursor::pos());
QTest::qSleep(100);
}
}
void MouseBlocker::die()
{
this->alive = false;
while (this->isRunning()) QTest::qSleep(10);
}

View File

@ -1,20 +0,0 @@
#ifndef MOUSEBLOCKER_H
#define MOUSEBLOCKER_H
#include <QThread>
class MouseBlocker : public QThread
{
Q_OBJECT
bool alive;
public:
explicit MouseBlocker(QObject *parent = 0);
void run();
void die();
signals:
public slots:
};
#endif // MOUSEBLOCKER_H

View File

@ -1,4 +0,0 @@
moveMouse om newButton
clickWidget om newButton
hoverMenuItem newObjectPopup New\_Firewall
clickMenuItem newObjectPopup New\_Firewall

View File

@ -1,11 +0,0 @@
moveMouse w#newFirewallDialog obj_name
clickMouse w#newFirewallDialog obj_name
typeWidget w#newFirewallDialog obj_name guardian
selectComboItem w#newFirewallDialog platform iptables
selectComboItem w#newFirewallDialog hostOS Linux\_2.4/2.6
moveMouse w#newFirewallDialog useTemplate
clickWidget w#newFirewallDialog useTemplate
moveMouse w#newFirewallDialog templateUseStandart
clickWidget w#newFirewallDialog templateUseStandart
moveMouse w#newFirewallDialog nextButton
clickWidget w#newFirewallDialog nextButton

View File

@ -1,3 +0,0 @@
selectListItem w#newFirewallDialog templateList fw\_template\_3
moveMouse w#newFirewallDialog nextButton
clickWidget w#newFirewallDialog nextButton

View File

@ -1,5 +0,0 @@
selectTab w#newFirewallDialog interfaceEditor2 1
selectTab w#newFirewallDialog interfaceEditor2 2
selectTab w#newFirewallDialog interfaceEditor2 0
moveMouse w#newFirewallDialog finishButton
clickWidget w#newFirewallDialog finishButton

View File

@ -1,4 +0,0 @@
#page requiresPrevPageDemonstrated prevEnabled undoActionCount
0 true false
1 true false
2 true false

View File

@ -1,3 +1,3 @@
<p>This page of the wizard shows template objects and their configuration. Standard template objects represent firewalls with two or three interfaces, a host with one interface, a web server or a Cisco router. We'll choose fw template 3, a firewall with three interfaces, for this example. Click Finish to create a new firewall object using the chosen template.</p>
<img src=":/Tutorial/images/2.png">
<p>This page of the wizard shows template objects and their configuration. Standard template objects represent firewalls with two or three interfaces, a host with one interface, a web server or a Cisco router. We'll choose fw template 3, a firewall with three interfaces, for this example. Click Finish to create a new firewall object using the chosen template.</p><br>
<img src=":/Tutorial/images/2.png"><br>
<p>Clicking "Next" brings us to the next page of the wizard where we can change configuration of the interfaces of the template firewall.</p>

View File

@ -1,379 +0,0 @@
#include "TutorialAnimator.h"
#include "../../config.h"
#include "global.h"
#include "utils.h"
#include "utils_no_qt.h"
#include "platforms.h"
#include "FWWindow.h"
#include <QApplication>
#include <QDebug>
#include <QComboBox>
#include <QTest>
#include <QTimer>
Q_DECLARE_METATYPE(QMenu*);
using namespace libfwbuilder;
using namespace std;
TutorialAnimator::TutorialAnimator(QObject *parent, QString commands) :
QThread(parent)
{
qRegisterMetaType<QMenu*>("QMenu*");
// widget = new QWidget(dynamic_cast<QWidget*>(this->parent()));
// widget->setFocus(Qt::ActiveWindowFocusReason);
//dynamic_cast<QWidget*>(parent)->grabKeyboard();
//dynamic_cast<QWidget*>(parent)->grabMouse();
dynamic_cast<QWidget*>(parent)->hide();
dynamic_cast<QWidget*>(parent)->setWindowModality(Qt::NonModal);
currentCommand = 0;
this->commands = commands.split('\n');
helper = new TutorialHelper(this);
connect(this, SIGNAL(finished()), this, SLOT(scenarioFinished()));
this->speed = 50;
}
TutorialAnimator::~TutorialAnimator()
{
delete helper;
}
void TutorialAnimator::scenarioFinished()
{
//dynamic_cast<QWidget*>(this->parent())->releaseKeyboard();
//dynamic_cast<QWidget*>(this->parent())->releaseMouse();
dynamic_cast<QWidget*>(parent())->setWindowModality(Qt::ApplicationModal);
dynamic_cast<QWidget*>(this->parent())->show();
/*
dynamic_cast<QWidget*>(this->parent())->grabMouse();
dynamic_cast<QWidget*>(this->parent())->grabKeyboard();
dynamic_cast<QWidget*>(this->parent())->releaseKeyboard();
dynamic_cast<QWidget*>(this->parent())->releaseMouse();
*/
dynamic_cast<QWidget*>(this->parent())->raise();
}
void TutorialAnimator::run()
{
this->helper->blockMouse(true);
this->helper->blockInput(true);
for (int i=0; i<this->commands.count(); i++)
{
animate(i);
QTest::qWait(speed*20);
}
this->helper->blockMouse(false);
this->helper->blockInput(false);
//w->releaseKeyboard();
//w->releaseMouse();
}
void TutorialAnimator::animate(int command)
{
if (command == -1) command = currentCommand;
QStringList input = commands.at(command).split(QRegExp("\\s+"));
for(int i=0; i<input.size(); i++)
{
QString str = input.at(i);
input[i] = str.replace(QRegExp("\\\\_"), " ");
}
QString baseCommand = input.first().trimmed();
input.removeFirst();
if (baseCommand == "moveMouse")
moveMouse(input); // input: widget_tree OR x y
if (baseCommand == "clickWidget")
clickWidget(input); // input: widget_tree
if (baseCommand == "typeWidget")
typeWidget(input); // input: widget_tree text
if (baseCommand == "hoverMenuItem")
hoverMenuItem(input); // input: menu_name item_name
if (baseCommand == "clickMenuItem")
clickMenuItem(input); // input: menu_name item_name
if (baseCommand == "selectComboItem")
selectComboItem(input); // input: widget_tree item_index
if (baseCommand == "selectListItem")
selectListItem(input); // input: widget_tree item_index
if (baseCommand == "selectTab")
selectTab(input); // input: widget_tree item_index
if (baseCommand == "wait")
wait(input);
}
QObject* TutorialAnimator::findChild(QObject *parent, QString name)
{
bool lookingForClass = false;
if (name.startsWith("w#"))
{
name.remove(0, 2);
lookingForClass = true;
qDebug() << "looking for class" << name;
}
QObjectList queue;
queue.append(parent);
while(queue.size())
{
QObject *obj = queue.first();
queue.removeFirst();
if ( ( (!lookingForClass) && (obj->objectName() == name) ) ||
( (lookingForClass) && (obj->metaObject()->className() == name) ) )
{
return obj;
}
else
{
queue += obj->children();
}
}
return NULL;
}
QWidget* TutorialAnimator::findWidget(QString name)
{
bool lookingForClass = false;
if (name.startsWith("w#"))
{
name.remove(0, 2);
lookingForClass = true;
}
foreach(QWidget *w, app->allWidgets())
{
if ( ( (!lookingForClass) && (w->objectName() == name) ) ||
( (lookingForClass) && (w->metaObject()->className() == name) ) )
return w;
}
return NULL;
}
QObject* TutorialAnimator::getWidget(QStringList input)
{
QObject *obj = findChild(mw, input.first());
if (obj == NULL)
{
obj = findWidget(input.first());
if (obj == NULL)
{
qDebug() << "could not find such object";
return NULL;
}
}
input.removeFirst();
if (!input.empty())
foreach (QString name, input)
{
obj = findChild(obj, name);
if (obj == NULL)
{
qDebug() << "could not find such object";
return NULL;
}
}
if (obj == NULL)
{
qDebug() << "could not find such object";
return NULL;
}
return obj;
}
void TutorialAnimator::moveMouse(QStringList input)
{
qDebug() << "input:" << input;
// is first two arguments are ints, click mouse at this coordintates
bool isInt1 = false, isInt2 = false;
int x, y;
if (input.size() == 2)
{
x = input.at(0).toInt(&isInt1, 10);
y = input.at(1).toInt(&isInt2, 10);
}
if (isInt1 && isInt2)
{
qDebug() << "moving mouse to (" << x << "," << y << ")";
helper->moveMouse(QPoint(x,y));
}
// if not, they should be widget names
// find widget with name of last argument who's parent is previous argument recursively
else
{
QObject *obj = getWidget(input);
helper->moveMouse(dynamic_cast<QWidget*>(obj));
}
}
QPoint TutorialAnimator::findMenuItemPos(QMenu *menu, QString item)
{
int x = menu->width()/2;
int top, bottom;
for (int i=1; i<menu->height()-1; i++)
{
QAction *action = menu->actionAt(QPoint(x,i));
if (action == NULL) continue;
if (action->text() == item)
{
top = i;
break;
}
}
for (int i=menu->height()-1; i>1; i--)
{
QAction *action = menu->actionAt(QPoint(x,i));
if (action == NULL) continue;
if (action->text() == item)
{
bottom = i;
break;
}
}
if (top==bottom) return QPoint();
return QPoint(x, (top+bottom)/2);
}
QWidget* TutorialAnimator::topLevelWindow(QString className)
{
foreach (QWidget *w, app->topLevelWidgets())
{
if (w->metaObject()->className() == className)
return w;
}
return NULL;
}
void TutorialAnimator::hoverMenuItem(QStringList input)
{
QMenu *menu = dynamic_cast<QMenu*>(findWidget(input.first()));
if (menu == NULL)
{
qDebug() << "could not find menu" << input.first();
return;
}
QPoint pos = findMenuItemPos(menu, input.at(1));
helper->moveMouse(dynamic_cast<QWidget*>(menu), pos);
}
void TutorialAnimator::clickMenuItem(QStringList input)
{
QMenu *menu = dynamic_cast<QMenu*>(findWidget(input.first()));
if (menu == NULL)
{
qDebug() << "could not find menu" << input.first();
return;
}
QPoint pos = findMenuItemPos(menu, input.at(1));
QTest::mouseMove(menu, pos);
QMetaObject::invokeMethod(helper, "clickMenuItem", Qt::QueuedConnection,
Q_ARG(QMenu*, menu), Q_ARG(QPoint, pos));
}
void TutorialAnimator::wait(QStringList input)
{
if (input.size() < 1)
{
qDebug() << "Wrong command";
return;
}
bool isInt = false;
int n = input.first().toInt(&isInt, 10);
if (isInt == false)
{
qDebug() << "Wrong command";
return;
}
QTest::qWait(n);
}
void TutorialAnimator::clickWidget(QStringList input)
{
if (input.size() < 1)
{
qDebug() << "Wrong command";
return;
}
QWidget *w = dynamic_cast<QWidget*>(getWidget(input));
if (w == NULL)
{
qDebug() << "Could not find widget:" << input;
return;
}
QTest::mouseMove(w);
QMetaObject::invokeMethod(helper, "clickWidget", Qt::QueuedConnection, Q_ARG(QWidget*, w));
}
void TutorialAnimator::typeWidget(QStringList input)
{
if (input.size() < 2)
{
qDebug() << "Wrong command";
return;
}
QString text = input.last();
input.pop_back();
QWidget *w = dynamic_cast<QWidget*>(getWidget(input));
if (w == NULL)
{
qDebug() << "Could not find widget:" << input;
return;
}
QMetaObject::invokeMethod(helper, "typeWidget", Qt::QueuedConnection,
Q_ARG(QWidget*, w), Q_ARG(QString, text));
QTest::qWait(text.length()*speed);
}
void TutorialAnimator::selectComboItem(QStringList input)
{
QString idstr = input.last();
bool isId;
int id = idstr.toInt(&isId, 10);
input.pop_back();
QComboBox *combo = dynamic_cast<QComboBox*>(this->getWidget(input));
if (isId)
QMetaObject::invokeMethod(helper, "selectComboItem", Qt::BlockingQueuedConnection,
Q_ARG(QWidget*, dynamic_cast<QWidget*>(combo)), Q_ARG(int, id));
else
QMetaObject::invokeMethod(helper, "selectComboItem", Qt::BlockingQueuedConnection,
Q_ARG(QWidget*, dynamic_cast<QWidget*>(combo)), Q_ARG(QString, idstr));
}
void TutorialAnimator::selectListItem(QStringList input)
{
QString idstr = input.last();
bool isId;
int id = idstr.toInt(&isId, 10);
input.pop_back();
qDebug() << "view:" << this->getWidget(input);
QAbstractItemView *combo = dynamic_cast<QAbstractItemView*>(this->getWidget(input));
qDebug() << "selecting list item:" << combo;
if (isId)
QMetaObject::invokeMethod(helper, "selectListItem", Qt::BlockingQueuedConnection,
Q_ARG(QWidget*, dynamic_cast<QWidget*>(combo)), Q_ARG(int, id));
else
QMetaObject::invokeMethod(helper, "selectListItem", Qt::BlockingQueuedConnection,
Q_ARG(QWidget*, dynamic_cast<QWidget*>(combo)), Q_ARG(QString, idstr));
}
void TutorialAnimator::selectTab(QStringList input)
{
QString idstr = input.last();
bool isId;
int id = idstr.toInt(&isId, 10);
input.pop_back();
qDebug() << "view:" << this->getWidget(input);
QTabWidget *combo = dynamic_cast<QTabWidget*>(this->getWidget(input));
qDebug() << "selecting tab in widget:" << combo;
if (isId)
QMetaObject::invokeMethod(helper, "selectTab", Qt::BlockingQueuedConnection,
Q_ARG(QWidget*, dynamic_cast<QWidget*>(combo)), Q_ARG(int, id));
else
QMetaObject::invokeMethod(helper, "selectTab", Qt::BlockingQueuedConnection,
Q_ARG(QWidget*, dynamic_cast<QWidget*>(combo)), Q_ARG(QString, idstr));
}
void TutorialAnimator::setSpeed(int speed)
{
this->speed = speed;
this->helper->speed = speed;
}

View File

@ -1,52 +0,0 @@
#ifndef TUTORIALANIMATOR_H
#define TUTORIALANIMATOR_H
#include <QMenu>
#include <QPoint>
#include <QThread>
#include <QObject>
#include <QStringList>
#include <QAction>
#include "TutorialHelper.h"
class TutorialAnimator : public QThread
{
Q_OBJECT
int speed;
TutorialHelper *helper;
QWidget *widget;
QStringList commands;
int currentCommand;
void animate(int command);
void moveMouse(QStringList input);
void clickWidget(QStringList input);
void typeWidget(QStringList input);
void wait(QStringList input);
void hoverMenuItem(QStringList input);
void clickMenuItem(QStringList input);
void selectComboItem(QStringList input);
void selectListItem(QStringList input);
void selectTab(QStringList input);
public:
explicit TutorialAnimator(QObject *parent, QString commands);
~TutorialAnimator();
void run();
void setSpeed(int speed);
QObject* findChild(QObject *parent, QString name);
QWidget* findWidget(QString name);
QPoint findMenuItemPos(QMenu *menu, QString item);
QObject* getWidget(QStringList input);
QWidget* topLevelWindow(QString);
public slots:
void scenarioFinished();
};
#endif // TUTORIALANIMATOR_H

View File

@ -9,25 +9,9 @@ TutorialDialog::TutorialDialog(QWidget *parent) :
ui(new Ui::TutorialDialog_q)
{
ui->setupUi(this);
animator = NULL;
currentPage = 0;
this->setWindowFlags(this->windowFlags() | Qt::WindowStaysOnTopHint);
this->setWindowModality(Qt::ApplicationModal);
QFile f(QString(":/Tutorial/controls.txt"));
f.open(QFile::ReadOnly);
foreach(QString line, QString(f.readAll()).split("\n"))
{
QStringList parts = line.split(" ");
if (parts.size() < 3) continue;
bool ok;
int page = parts.at(0).toInt(&ok, 10);
prevEnabled[page] = parts.at(2) == "true";
requiresPrev[page] = parts.at(1) == "true";
qDebug() << requiresPrev;
}
//this->setWindowModality(Qt::ApplicationModal);
showPage(currentPage);
}
@ -61,67 +45,25 @@ void TutorialDialog::next()
void TutorialDialog::previous()
{
runScenario(getUndoForPage(currentPage));
currentPage--;
showPage(currentPage);
}
void TutorialDialog::reset()
{
runScenario(getResetForPage(currentPage));
currentPage = 0;
showPage(currentPage);
}
void TutorialDialog::runScenario(QString scenario)
{
if (animator != NULL) animator->deleteLater();
animator = new TutorialAnimator(this, scenario);
animator->setSpeed(ui->speed->value());
animator->start();
}
QString TutorialDialog::getScenarioForPage(int page)
{
QFile src(QString(":/Tutorial/commands/page") + QString::number(page) + ".txt");
src.open(QFile::ReadOnly);
return QString(src.readAll());
}
QString TutorialDialog::getUndoForPage(int page)
{
QFile src(QString(":/Tutorial/prev-commands/page") + QString::number(page) + ".txt");
src.open(QFile::ReadOnly);
return QString(src.readAll());
}
QString TutorialDialog::getResetForPage(int page)
{
QFile src(QString(":/Tutorial/reset-commands/page") + QString::number(page) + ".txt");
src.open(QFile::ReadOnly);
return QString(src.readAll());
}
void TutorialDialog::showPage(int page)
{
ui->demonstrate->setEnabled(true);
QString filename = QString(":/Tutorial/html/page") + QString::number(page) + ".html";
QFile src(filename);
src.open(QFile::ReadOnly);
QString text = src.readAll();
ui->content->setText(text);
qDebug() << "next should be enabled:" << page+1 << requiresPrev[page+1];
bool nextPageExists = QFile::exists(QString(":/Tutorial/html/page") + QString::number(page+1) + ".html");
ui->next->setEnabled(nextPageExists && (!requiresPrev[page+1]));
ui->message->setVisible(nextPageExists && requiresPrev[page+1]);
ui->prev->setEnabled(prevEnabled[page]);
}
void TutorialDialog::demonstrate()
{
ui->demonstrate->setEnabled(false);
runScenario(getScenarioForPage(currentPage));
ui->next->setEnabled(QFile::exists(QString(":/Tutorial/html/page") + QString::number(currentPage+1) + ".html"));
if (QFile::exists(QString(":/Tutorial/html/page") + QString::number(currentPage+1) + ".html"))
showPage(++currentPage);
bool prevPageExists = QFile::exists(QString(":/Tutorial/html/page") + QString::number(page-1) + ".html");
ui->next->setEnabled(nextPageExists);
ui->prev->setEnabled(prevPageExists);
}

View File

@ -2,7 +2,6 @@
#define TUTORIALDIALOG_H
#include <QDialog>
#include "TutorialAnimator.h"
namespace Ui {
@ -28,15 +27,11 @@ protected:
private:
Ui::TutorialDialog_q *ui;
int currentPage;
TutorialAnimator *animator;
QMap<int, bool> prevEnabled;
QMap<int, bool> requiresPrev;
public slots:
void previous();
void next();
void reset();
void demonstrate();
void showPage(int page);
};

View File

@ -31,7 +31,7 @@
<x>0</x>
<y>0</y>
<width>136</width>
<height>494</height>
<height>562</height>
</rect>
</property>
<property name="sizePolicy">
@ -64,72 +64,6 @@
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Speed:</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="speed">
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="minimum">
<number>30</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="demonstrate">
<property name="text">
<string>Demonstrate</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="message">
<property name="text">
<string>View demonstration to proceed to next step.</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="sizeConstraint">
@ -205,6 +139,19 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
@ -212,14 +159,14 @@
<resources/>
<connections>
<connection>
<sender>next</sender>
<sender>reset</sender>
<signal>clicked()</signal>
<receiver>TutorialDialog_q</receiver>
<slot>next()</slot>
<slot>reset()</slot>
<hints>
<hint type="sourcelabel">
<x>421</x>
<y>514</y>
<x>340</x>
<y>619</y>
</hint>
<hint type="destinationlabel">
<x>241</x>
@ -234,8 +181,8 @@
<slot>previous()</slot>
<hints>
<hint type="sourcelabel">
<x>217</x>
<y>514</y>
<x>242</x>
<y>619</y>
</hint>
<hint type="destinationlabel">
<x>241</x>
@ -244,14 +191,14 @@
</hints>
</connection>
<connection>
<sender>reset</sender>
<sender>next</sender>
<signal>clicked()</signal>
<receiver>TutorialDialog_q</receiver>
<slot>reset()</slot>
<slot>next()</slot>
<hints>
<hint type="sourcelabel">
<x>319</x>
<y>514</y>
<x>438</x>
<y>619</y>
</hint>
<hint type="destinationlabel">
<x>241</x>
@ -260,18 +207,18 @@
</hints>
</connection>
<connection>
<sender>demonstrate</sender>
<sender>pushButton</sender>
<signal>clicked()</signal>
<receiver>TutorialDialog_q</receiver>
<slot>demonstrate()</slot>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>410</x>
<y>472</y>
<x>507</x>
<y>603</y>
</hint>
<hint type="destinationlabel">
<x>241</x>
<y>271</y>
<x>551</x>
<y>609</y>
</hint>
</hints>
</connection>
@ -280,6 +227,5 @@
<slot>previous()</slot>
<slot>next()</slot>
<slot>reset()</slot>
<slot>demonstrate()</slot>
</slots>
</ui>

View File

@ -1,211 +0,0 @@
#include "TutorialHelper.h"
#include <QTest>
#include <QDebug>
#include <QMenu>
#include <QAbstractItemView>
#include <QDesktopWidget>
#include <QApplication>
#include <QCursor>
#include "global.h"
#include "FWWindow.h"
#include "TutorialAnimator.h"
TutorialHelper::TutorialHelper(QObject* parent): QObject(parent)
{
speed = 50;
widget = dynamic_cast<QWidget*>(parent->parent());//NULL;
mouseBlocker = NULL;
}
void TutorialHelper::blockInput(bool block)
{
if (block)
{
if (this->widget == NULL)
this->widget = new QWidget();
this->widget->grabKeyboard();
this->widget->grabMouse();
}
else
{
if (this->widget == NULL) return;
this->widget->releaseKeyboard();
this->widget->releaseMouse();
}
}
void TutorialHelper::blockMouse(bool block)
{
if (block)
{
if (mouseBlocker == NULL)
mouseBlocker = new MouseBlocker();
mouseBlocker->start();
}
else
{
if (mouseBlocker == NULL) return;
mouseBlocker->die();
mouseBlocker->terminate();
// mouseBlocker->deleteLater();
delete mouseBlocker;
mouseBlocker = NULL;
}
}
void TutorialHelper::moveMouse(QPoint end)
{
qreal distance = QLineF(QCursor::pos(), end).length();
qreal screenSize = QLineF(QPoint(0,0), QApplication::desktop()->geometry().bottomRight()).length();
qreal time = (speed*2) * distance / screenSize;
qreal step = distance / time;
int timestep = time / (distance/step);
while (QLineF(QCursor::pos(), end).length() > step)
{
QLineF line(QCursor::pos(), end);
line.setLength(step);
QCursor::setPos(line.p2().toPoint());
QTest::qWait(timestep);
}
QCursor::setPos(end);
}
void TutorialHelper::moveMouse(QWidget *w, QPoint userpoint)
{
QPoint pos;
if (userpoint == QPoint(-1,-1))
pos = w->mapToGlobal(w->rect().center());
else
pos = w->mapToGlobal(userpoint);
moveMouse(pos);
}
void TutorialHelper::clickWidget(QWidget *w)
{
this->blockInput(false);
QTest::mouseClick(w, Qt::LeftButton, Qt::NoModifier, QPoint(), speed*4);
this->blockInput(true);
}
void TutorialHelper::clickMenuItem(QMenu *menu, QPoint pos)
{
this->blockInput(false);
QTest::mouseClick(menu, Qt::LeftButton, Qt::NoModifier, pos, speed);
this->blockInput(true);
}
void TutorialHelper::typeWidget(QWidget *w, QString text)
{
this->blockInput(false);
QTest::keyClicks(w, text, Qt::NoModifier, 50);
this->blockInput(true);
}
QPoint TutorialHelper::findViewItem(QAbstractItemView *view, int id)
{
int x = view->width() / 5;
int top = -1, bottom = -1;
for (top=0; top<view->height(); top++)
{
if (view->indexAt(QPoint(x, top)).row() == id)
break;
}
for (bottom=view->height(); bottom != 0; bottom--)
{
if (view->indexAt(QPoint(x, bottom)).row() == id)
break;
}
return QPoint(x, (top+bottom)/2);
}
void TutorialHelper::selectComboItem(QWidget *widget, int id)
{
QComboBox * combo = dynamic_cast<QComboBox*>(widget);
moveMouse(combo);
this->blockInput(false);
QTest::mouseClick(combo, Qt::LeftButton);
this->blockInput(true);
QPoint itemPos = this->findViewItem(combo->view(), id);
QTest::qWait(speed*4);
moveMouse(combo->view(), itemPos);
this->blockInput(false);
QTest::mouseClick(combo->view(), Qt::LeftButton, 0, itemPos);
this->blockInput(true);
}
void TutorialHelper::selectComboItem(QWidget *widget, QString name)
{
QComboBox * combo = dynamic_cast<QComboBox*>(widget);
int id = combo->findText(name);
selectComboItem(widget, id);
}
void TutorialHelper::selectListItem(QWidget *widget, int id)
{
QAbstractItemView *view = dynamic_cast<QAbstractItemView*>(widget);
QPoint itemPos = findViewItem(view, id);
view->scrollTo(view->indexAt(itemPos));
itemPos = findViewItem(view, id);
moveMouse(view, itemPos);
view->setCurrentIndex(view->indexAt(itemPos));
this->blockInput(false);
QTest::mouseClick(view, Qt::LeftButton, 0, itemPos);
this->blockInput(true);
}
void TutorialHelper::selectListItem(QWidget *widget, QString name)
{
QAbstractItemView * view = dynamic_cast<QAbstractItemView*>(widget);
int id = 0;
for (; id < view->model()->rowCount(); id++)
if (view->model()->data(view->model()->index(id, 0, QModelIndex())).toString() == name)
break;
selectListItem(widget, id);
}
class PublicTabBar : public QTabWidget { public: using QTabWidget::tabBar; };
QPoint findTab(QTabBar *bar, int id)
{
int x = bar->width()/2;
int top, bottom, left, right;
for (top=0; top<bar->height(); top++)
if (bar->tabAt(QPoint(x, top)) == id)
break;
for (bottom = bar->height(); bottom != 0; bottom--)
if (bar->tabAt(QPoint(x, bottom)) == id)
break;
int y = bar->height()/2;
for (left = 0; left < bar->width(); left++)
if (bar->tabAt(QPoint(left, y)) == id)
break;
for (right = bar->width(); right!=0; right--)
if (bar->tabAt(QPoint(right, y)) == id)
break;
return QPoint((left+right)/2, (top+bottom)/2);
}
void TutorialHelper::selectTab(QWidget *widget, int id)
{
QTabBar *bar = dynamic_cast<QTabBar*>(dynamic_cast<TutorialAnimator*>(parent())->findChild(widget, "w#QTabBar"));
QPoint pos = findTab(bar, id);
moveMouse(bar, pos);
QTest::qWait(speed*4);
this->blockInput(false);
QTest::mouseClick(bar, Qt::LeftButton, 0, pos);
this->blockInput(true);
}
void TutorialHelper::selectTab(QWidget *widget, QString name)
{
QTabWidget * view = dynamic_cast<QTabWidget*>(widget);
int id = 0;
for (; id < view->count(); id++)
if (view->tabText(id) == name)
break;
selectTab(widget, id);
}

View File

@ -1,36 +0,0 @@
#ifndef TUTORIALHELPER_H
#define TUTORIALHELPER_H
#include <QObject>
#include <QMenu>
#include <QComboBox>
#include "MouseBlocker.h"
class TutorialHelper : public QObject
{
Q_OBJECT
QWidget *widget;
MouseBlocker *mouseBlocker;
public:
int speed;
TutorialHelper(QObject *parent = NULL);
public slots:
void clickWidget(QWidget*);
void clickMenuItem(QMenu *menu, QPoint pos);
void typeWidget(QWidget *w, QString text);
void selectComboItem(QWidget *box, int id);
void selectComboItem(QWidget *box, QString name);
void selectListItem(QWidget *box, int id);
void selectListItem(QWidget *box, QString name);
void moveMouse(QPoint end);
void moveMouse(QWidget *w, QPoint userpoint = QPoint(-1,-1));
void selectTab(QWidget *widget, QString name);
void selectTab(QWidget *widget, int id);
void blockInput(bool value);
void blockMouse(bool value);
QPoint findViewItem(QAbstractItemView *view, int id);
};
#endif // TUTORIALHELPER_H

View File

@ -175,10 +175,7 @@ HEADERS += ../../config.h \
FWCmdRule.h \
UsageResolver.h \
IconSetter.h \
TutorialAnimator.h \
TutorialDialog.h \
TutorialHelper.h \
MouseBlocker.h
TutorialDialog.h
SOURCES += ProjectPanel.cpp \
ProjectPanel_events.cpp \
ProjectPanel_file_ops.cpp \
@ -351,10 +348,7 @@ SOURCES += ProjectPanel.cpp \
FWCmdRule.cpp \
IconSetter.cpp \
UsageResolver.cpp \
TutorialAnimator.cpp \
TutorialDialog.cpp \
TutorialHelper.cpp \
MouseBlocker.cpp
TutorialDialog.cpp
FORMS = FWBMainWindow_q.ui \
compileroutputpanel_q.ui \
customservicedialog_q.ui \