Developer Documentation
baseWidget.cc
1/*===========================================================================*\
2* *
3* OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39* *
40\*===========================================================================*/
41
42
43
44//== INCLUDES =================================================================
45#include <QVBoxLayout>
46#include <QPushButton>
47#include <QDialog>
48#include <QTextEdit>
49#include <QFileDialog>
50#include <QMenu>
51#include <QMenuBar>
52#include <QMessageBox>
53
54#include <QApplication>
55#include <QClipboard>
56
57#include <QDomDocument>
58
60
61#include "baseWidget.hh"
62#include "toolBoxElement.hh"
63#include "scene/sceneElement.hh"
64
65#include "parser/context.hh"
66
67//== NAMESPACES ===============================================================
68namespace VSI {
69
70//=============================================================================
71//
72// CLASS BaseWidget - IMPLEMENTATION
73//
74//=============================================================================
75
76// static variable for singleton
77BaseWidget * BaseWidget::base_ = NULL;
78
79//------------------------------------------------------------------------------
80
81// Constructor
82BaseWidget::BaseWidget (Context *_ctx, QWidget *_parent) :
83 QMainWindow (_parent),
84 ctx_ (_ctx),
85 fileName_ (),
86 changedContent_ (false)
87{
88 setWindowIcon (OpenFlipper::Options::OpenFlipperIcon ());
89 updateTitle ();
90
91 splitter_ = new QSplitter (Qt::Horizontal, this);
92 toolbox_ = new QToolBox ();
93 views_ = new QStackedWidget ();
94
95
96 toolbox_->setMinimumWidth (275);
97
98 QVBoxLayout *layout = new QVBoxLayout;
99
100 layout->addWidget (toolbox_);
101
102 QPushButton *execute = new QPushButton ("Execute");
103 layout->addWidget (execute);
104
105 QWidget *w = new QWidget;
106 w->setLayout (layout);
107
108 mainScene_ = new GraphicsScene (_ctx);
109 views_->addWidget(mainScene_->graphicsView ());
110
111 splitter_->addWidget (w);
112 splitter_->addWidget (views_);
113 QList<int> sizes;
114 sizes << 275 << 10000;
115 splitter_->setSizes (sizes);
116
117 setCentralWidget (splitter_);
118
119 resize (1000, 700);
120
121 setupUi ();
122
123 connect (execute, SIGNAL (clicked (bool)), this, SLOT (executeCode ()));
124
125 connect (mainScene_, SIGNAL (contentChanged()), this, SLOT (contentChanged()));
126
127
128 QMenu *menu = new QMenu (tr("&File"));
129 QIcon icon;
130
131 icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"add-empty-object.png");
132 menu->addAction (icon, tr("New"), this, SLOT (newFile()), QKeySequence::New);
133
134 icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"document-open.png");
135 menu->addAction (icon, tr("Open ..."), this, SLOT (load()), QKeySequence::Open);
136
137 menu->addSeparator ();
138
139 icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"document-save.png");
140 menu->addAction (icon, tr("Save"), this, SLOT (save()), QKeySequence::Save);
141
142 icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"document-save-as.png");
143 menu->addAction (icon, tr("Save as ..."), this, SLOT (saveAs()), QKeySequence::SaveAs);
144 menu->addSeparator ();
145
146 icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"window-close.png");
147 menu->addAction (icon, tr("Close"), this, SLOT (close()), QKeySequence::Close);
148
149 menuBar()->addMenu (menu);
150
151 menu = new QMenu (tr("&Script"));
152 icon.addFile(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"scriptEditor.png");
153 menu->addAction (icon, tr("Open in script editor"), this, SLOT (codeToScript()));
154
155 menuBar()->addMenu (menu);
156
157 base_ = this;
158}
159
160//------------------------------------------------------------------------------
161
163BaseWidget::~BaseWidget ()
164{
165 base_ = NULL;
166}
167
168//------------------------------------------------------------------------------
169
171void BaseWidget::setupUi ()
172{
173
174 foreach (const QString &c, ctx_->categories ())
175 {
176 QWidget *widget = new QWidget (toolbox_);
177 QVBoxLayout *layout = new QVBoxLayout ();
178 foreach (Element *e, ctx_->elements (c))
179 {
180 if (!(e->flags () & ELEMENT_FLAG_SKIP_TOOLBOX))
181 {
182 ToolBoxElement *t = new ToolBoxElement (e, widget);
183 layout->addWidget (t);
184 }
185 }
186 layout->addStretch ();
187 widget->setLayout (layout);
188 toolbox_->addItem (widget, c);
189 }
190}
191
192//------------------------------------------------------------------------------
193
195void BaseWidget::executeCode ()
196{
197 QString errors = "";
198
199 QString code = mainScene_->generateCode (errors);
200
201 if (errors.isEmpty ())
202 {
203 ctx_->executeScript(code);
204 return;
205 }
206
207 errors = "<h3> " + tr("Following Elements could not be processed:") + "</h3>" + errors;
208
209 QMessageBox::warning (this, tr("Error during code generation"), errors, QMessageBox::Ok);
210}
211
212//------------------------------------------------------------------------------
213
215void BaseWidget::codeToScript()
216{
217
218 QString errors = "";
219
220 QString code = mainScene_->generateCode (errors);
221
222 if (errors.isEmpty ())
223 {
224 emit codeToScriptEditor (code);
225 return;
226 }
227
228 errors = "<qt> " + tr("Following Elements could not be processed:") + errors + "</qt>";
229
230 QMessageBox::warning (this, tr("Error during code generation"), errors,QMessageBox::Ok);
231}
232
233//------------------------------------------------------------------------------
234
236bool BaseWidget::saveAs()
237{
238 return save (true);
239}
240
241//------------------------------------------------------------------------------
242
245{
246 if (!saveIfChanged ())
247 return;
248
249 QString filename = QFileDialog::getOpenFileName (this,
250 tr("Load Visual Script"),
251 OpenFlipperSettings().value("Core/CurrentDir").toString(),
252 tr("Visual Script File (*.ofvs)"));
253
254 if (filename.isEmpty ())
255 return;
256
257 // Get the chosen directory and remember it.
258 QFileInfo fileInfo(filename);
259 OpenFlipperSettings().setValue("Core/CurrentDir", fileInfo.absolutePath() );
260
261 QFile f (filename);
262 if (!f.open (QFile::ReadOnly))
263 {
264 QMessageBox msgBox;
265 msgBox.setText(tr("Unable to open file."));
266 msgBox.setInformativeText(filename);
267 msgBox.exec();
268 return;
269 }
270
271 while (!scenes_.isEmpty())
272 scenes_.pop ();
273 views_->setCurrentWidget (mainScene_->graphicsView());
274
275
276 QDomDocument doc("OpenFlipper");
277 if (!doc.setContent(&f)) {
278 return;
279 }
280
281 // Iterate over all elements in the file (One Level below the OpenFlipper Tag
282 QDomElement docElem = doc.documentElement();
283 mainScene_->loadFromXml (docElem);
284
285
286
287 changedContent_ = false;
288 fileName_ = filename;
289 updateTitle ();
290}
291
292//------------------------------------------------------------------------------
293
295bool BaseWidget::save(bool _newName)
296{
297
298 QString filename;
299
300 if (fileName_.isEmpty () || _newName)
301 {
302 QFileDialog *d = new QFileDialog (this, tr("Save Visual Script"),
303 OpenFlipperSettings().value("Core/CurrentDir").toString(),
304 tr("Visual Script File (*.ofvs)"));
305
306 d->setAcceptMode (QFileDialog::AcceptSave);
307 d->setDefaultSuffix ("ofvs");
308
309 if (QDialog::Accepted == d->exec ())
310 filename = d->selectedFiles ()[0];
311 }
312 else
313 filename = fileName_;
314
315 if (filename.isEmpty ())
316 return false;
317
318 // Get the chosen directory and remember it.
319 QFileInfo fileInfo(filename);
320 OpenFlipperSettings().setValue("Core/CurrentDir", fileInfo.absolutePath() );
321
322 QFile f (filename);
323 if (!f.open (QFile::WriteOnly))
324 {
325 QMessageBox msgBox;
326 msgBox.setText(tr("Unable to write file."));
327 msgBox.setInformativeText(filename);
328 msgBox.exec();
329 return false;
330 }
331
332 QDomDocument doc("VisualScript");
333 QDomElement root = doc.createElement("VisualScript");
334 doc.appendChild(root);
335
336 mainScene_->saveToXml (doc, root);
337
338 f.write (doc.toString().toUtf8 ());
339 f.close ();
340
341 changedContent_ = false;
342 fileName_ = filename;
343 updateTitle ();
344
345 return true;
346}
347
348//------------------------------------------------------------------------------
349
352{
353 if (!saveIfChanged ())
354 return;
355
356 while (!scenes_.isEmpty())
357 scenes_.pop ();
358 views_->setCurrentWidget (mainScene_->graphicsView());
359
360 fileName_ = QString ();
361 mainScene_->clearScene ();
362 changedContent_ = false;
363 updateTitle ();
364}
365
366//------------------------------------------------------------------------------
367
370{
371 if (fileName_.isEmpty ())
372 setWindowTitle (tr("Untitled") + (changedContent_ ? " [" + tr("Modified") + "] " : "") + " - Visual Script Editor");
373 else
374 setWindowTitle (fileName_ + (changedContent_ ? " [" + tr("Modified") + "] " : "") + " - Visual Script Editor");
375}
376
377//------------------------------------------------------------------------------
378
381{
382 if (!changedContent_)
383 {
384 changedContent_ = true;
385 updateTitle ();
386 }
387}
388
389//------------------------------------------------------------------------------
390
393{
394 if (changedContent_)
395 {
396 QMessageBox msgBox;
397 msgBox.setText(tr("The visual script has been modified."));
398 msgBox.setInformativeText(tr("Do you want to save your changes?"));
399 msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
400 msgBox.setDefaultButton(QMessageBox::Save);
401 int ret = msgBox.exec();
402 switch (ret) {
403 case QMessageBox::Save:
404 // Save was clicked
405 if (!save ())
406 return false;
407 break;
408 case QMessageBox::Discard:
409 // Don't Save was clicked
410 break;
411 case QMessageBox::Cancel:
412 // Cancel was clicked
413 return false;
414 break;
415 default:
416 // should never be reached
417 break;
418 }
419 return true;
420 }
421 else
422 return true;
423}
424
425//------------------------------------------------------------------------------
426
428void BaseWidget::closeEvent(QCloseEvent *_event)
429{
430 if (!saveIfChanged ())
431 _event->ignore ();
432 else
433 _event->accept();
434}
435
436//------------------------------------------------------------------------------
437
440{
441 if (!base_)
442 base_ = new BaseWidget (_ctx, _parent);
443 return base_;
444}
445
446//------------------------------------------------------------------------------
447
450{
451 return base_;
452}
453
454//------------------------------------------------------------------------------
455
458{
459 scenes_.push (_scene);
460 views_->setCurrentWidget (_scene->graphicsView());
461}
462
463//------------------------------------------------------------------------------
464
467{
468 if (!scenes_.isEmpty())
469 scenes_.pop ();
470
471 if (!scenes_.isEmpty())
472 views_->setCurrentWidget (scenes_.top ()->graphicsView());
473 else
474 views_->setCurrentWidget (mainScene_->graphicsView());
475}
476
477//------------------------------------------------------------------------------
478
481{
482 views_->addWidget (_scene->graphicsView ());
483}
484
485//------------------------------------------------------------------------------
486
489{
490 views_->removeWidget (_scene->graphicsView ());
491}
492
493//------------------------------------------------------------------------------
494}
495
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
static BaseWidget * getBaseWidget()
Returns singleton.
Definition: baseWidget.cc:449
void popScene()
go back to last scene (function)
Definition: baseWidget.cc:466
void addScene(GraphicsScene *_scene)
add a new scene
Definition: baseWidget.cc:480
static BaseWidget * createBaseWidget(Context *_ctx, QWidget *_parent=NULL)
Singleton constructor.
Definition: baseWidget.cc:439
bool save(bool _newName=false)
save to file
Definition: baseWidget.cc:295
void updateTitle()
Update window title.
Definition: baseWidget.cc:369
bool saveIfChanged()
Asks the user if he want to save his changes.
Definition: baseWidget.cc:392
void contentChanged()
used changed something
Definition: baseWidget.cc:380
void pushScene(GraphicsScene *_scene)
show a new scene (function) in editor
Definition: baseWidget.cc:457
void newFile()
new empty file
Definition: baseWidget.cc:351
void load()
load file
Definition: baseWidget.cc:244
void removeScene(GraphicsScene *_scene)
remove a scene
Definition: baseWidget.cc:488
void closeEvent(QCloseEvent *_event)
Chatch close event.
Definition: baseWidget.cc:428
unsigned int flags() const
Flags.
Definition: element.hh:109
void loadFromXml(QDomElement &_domElement)
Load from xml.
void clearScene(bool _start=false)
clear the whole scene (_start = keep start element)
void saveToXml(QDomDocument &_doc, QDomElement &_root)
Save to xml.
GraphicsView * graphicsView()
Graphics view of the scene.