|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the tools applications of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include <qdeclarativeview.h> |
|
43 |
|
44 #ifdef hz |
|
45 #undef hz |
|
46 #endif |
|
47 #include "ui_recopts.h" |
|
48 |
|
49 #include "qmlruntime.h" |
|
50 #include <qdeclarativecontext.h> |
|
51 #include <qdeclarativeengine.h> |
|
52 #include <qdeclarativenetworkaccessmanagerfactory.h> |
|
53 #include "qdeclarative.h" |
|
54 #include <private/qabstractanimation_p.h> |
|
55 #include <QAbstractAnimation> |
|
56 |
|
57 #include <QSettings> |
|
58 #include <QXmlStreamReader> |
|
59 #include <QBuffer> |
|
60 #include <QNetworkReply> |
|
61 #include <QNetworkCookieJar> |
|
62 #include <QNetworkDiskCache> |
|
63 #include <QNetworkAccessManager> |
|
64 #include <QSignalMapper> |
|
65 #include <QDeclarativeComponent> |
|
66 #include <QWidget> |
|
67 #include <QApplication> |
|
68 #include <QTranslator> |
|
69 #include <QDir> |
|
70 #include <QTextBrowser> |
|
71 #include <QFile> |
|
72 #include <QFileInfo> |
|
73 #include <QVBoxLayout> |
|
74 #include <QProgressDialog> |
|
75 #include <QProcess> |
|
76 #include <QMenuBar> |
|
77 #include <QMenu> |
|
78 #include <QAction> |
|
79 #include <QFileDialog> |
|
80 #include <QTimer> |
|
81 #include <QGraphicsObject> |
|
82 #include <QNetworkProxyFactory> |
|
83 #include <QKeyEvent> |
|
84 #include <QMutex> |
|
85 #include <QMutexLocker> |
|
86 #include "proxysettings.h" |
|
87 #include "deviceorientation.h" |
|
88 |
|
89 #ifdef GL_SUPPORTED |
|
90 #include <QGLWidget> |
|
91 #endif |
|
92 |
|
93 #include <qdeclarativetester.h> |
|
94 |
|
95 #if defined (Q_OS_SYMBIAN) |
|
96 #define SYMBIAN_NETWORK_INIT |
|
97 #endif |
|
98 |
|
99 #if defined (SYMBIAN_NETWORK_INIT) |
|
100 #include <sys/types.h> |
|
101 #include <sys/stat.h> |
|
102 #include <fcntl.h> |
|
103 #include <unistd.h> |
|
104 #include <QTextCodec> |
|
105 #include "sym_iap_util.h" |
|
106 #endif |
|
107 |
|
108 QT_BEGIN_NAMESPACE |
|
109 |
|
110 class Runtime : public QObject |
|
111 { |
|
112 Q_OBJECT |
|
113 |
|
114 Q_PROPERTY(bool isActiveWindow READ isActiveWindow NOTIFY isActiveWindowChanged) |
|
115 Q_PROPERTY(DeviceOrientation::Orientation orientation READ orientation NOTIFY orientationChanged) |
|
116 |
|
117 public: |
|
118 static Runtime* instance() |
|
119 { |
|
120 static Runtime *instance = 0; |
|
121 if (!instance) |
|
122 instance = new Runtime; |
|
123 return instance; |
|
124 } |
|
125 |
|
126 bool isActiveWindow() const { return activeWindow; } |
|
127 void setActiveWindow(bool active) |
|
128 { |
|
129 if (active == activeWindow) |
|
130 return; |
|
131 activeWindow = active; |
|
132 emit isActiveWindowChanged(); |
|
133 } |
|
134 |
|
135 DeviceOrientation::Orientation orientation() const { return DeviceOrientation::instance()->orientation(); } |
|
136 |
|
137 Q_SIGNALS: |
|
138 void isActiveWindowChanged(); |
|
139 void orientationChanged(); |
|
140 |
|
141 private: |
|
142 Runtime(QObject *parent=0) : QObject(parent), activeWindow(false) |
|
143 { |
|
144 connect(DeviceOrientation::instance(), SIGNAL(orientationChanged()), |
|
145 this, SIGNAL(orientationChanged())); |
|
146 } |
|
147 |
|
148 bool activeWindow; |
|
149 }; |
|
150 |
|
151 |
|
152 class SizedMenuBar : public QMenuBar |
|
153 { |
|
154 Q_OBJECT |
|
155 public: |
|
156 SizedMenuBar(QWidget *parent, QWidget *referenceWidget) |
|
157 : QMenuBar(parent), refWidget(referenceWidget) |
|
158 { |
|
159 } |
|
160 |
|
161 virtual QSize sizeHint() const |
|
162 { |
|
163 return QSize(refWidget->sizeHint().width(), QMenuBar::sizeHint().height()); |
|
164 } |
|
165 |
|
166 private: |
|
167 QWidget *refWidget; |
|
168 }; |
|
169 |
|
170 static struct { const char *name, *args; } ffmpegprofiles[] = { |
|
171 {"Maximum Quality", "-sameq"}, |
|
172 {"High Quality", "-qmax 2"}, |
|
173 {"Medium Quality", "-qmax 6"}, |
|
174 {"Low Quality", "-qmax 16"}, |
|
175 {"Custom ffmpeg arguments", ""}, |
|
176 {0,0} |
|
177 }; |
|
178 |
|
179 class RecordingDialog : public QDialog, public Ui::RecordingOptions { |
|
180 Q_OBJECT |
|
181 |
|
182 public: |
|
183 RecordingDialog(QWidget *parent) : QDialog(parent) |
|
184 { |
|
185 setupUi(this); |
|
186 hz->setValidator(new QDoubleValidator(hz)); |
|
187 for (int i=0; ffmpegprofiles[i].name; ++i) { |
|
188 profile->addItem(ffmpegprofiles[i].name); |
|
189 } |
|
190 } |
|
191 |
|
192 void setArguments(QString a) |
|
193 { |
|
194 int i; |
|
195 for (i=0; ffmpegprofiles[i].args[0]; ++i) { |
|
196 if (ffmpegprofiles[i].args == a) { |
|
197 profile->setCurrentIndex(i); |
|
198 args->setText(QLatin1String(ffmpegprofiles[i].args)); |
|
199 return; |
|
200 } |
|
201 } |
|
202 customargs = a; |
|
203 args->setText(a); |
|
204 profile->setCurrentIndex(i); |
|
205 } |
|
206 |
|
207 QString arguments() const |
|
208 { |
|
209 int i = profile->currentIndex(); |
|
210 return ffmpegprofiles[i].args[0] ? QLatin1String(ffmpegprofiles[i].args) : customargs; |
|
211 } |
|
212 |
|
213 private slots: |
|
214 void pickProfile(int i) |
|
215 { |
|
216 if (ffmpegprofiles[i].args[0]) { |
|
217 args->setText(QLatin1String(ffmpegprofiles[i].args)); |
|
218 } else { |
|
219 args->setText(customargs); |
|
220 } |
|
221 } |
|
222 |
|
223 void storeCustomArgs(QString s) |
|
224 { |
|
225 setArguments(s); |
|
226 } |
|
227 |
|
228 private: |
|
229 QString customargs; |
|
230 }; |
|
231 |
|
232 class PersistentCookieJar : public QNetworkCookieJar { |
|
233 public: |
|
234 PersistentCookieJar(QObject *parent) : QNetworkCookieJar(parent) { load(); } |
|
235 ~PersistentCookieJar() { save(); } |
|
236 |
|
237 virtual QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const |
|
238 { |
|
239 QMutexLocker lock(&mutex); |
|
240 return QNetworkCookieJar::cookiesForUrl(url); |
|
241 } |
|
242 |
|
243 virtual bool setCookiesFromUrl(const QList<QNetworkCookie> &cookieList, const QUrl &url) |
|
244 { |
|
245 QMutexLocker lock(&mutex); |
|
246 return QNetworkCookieJar::setCookiesFromUrl(cookieList, url); |
|
247 } |
|
248 |
|
249 private: |
|
250 void save() |
|
251 { |
|
252 QMutexLocker lock(&mutex); |
|
253 QList<QNetworkCookie> list = allCookies(); |
|
254 QByteArray data; |
|
255 foreach (QNetworkCookie cookie, list) { |
|
256 if (!cookie.isSessionCookie()) { |
|
257 data.append(cookie.toRawForm()); |
|
258 data.append("\n"); |
|
259 } |
|
260 } |
|
261 QSettings settings; |
|
262 settings.setValue("Cookies",data); |
|
263 } |
|
264 |
|
265 void load() |
|
266 { |
|
267 QMutexLocker lock(&mutex); |
|
268 QSettings settings; |
|
269 QByteArray data = settings.value("Cookies").toByteArray(); |
|
270 setAllCookies(QNetworkCookie::parseCookies(data)); |
|
271 } |
|
272 |
|
273 mutable QMutex mutex; |
|
274 }; |
|
275 |
|
276 class NetworkAccessManagerFactory : public QDeclarativeNetworkAccessManagerFactory |
|
277 { |
|
278 public: |
|
279 NetworkAccessManagerFactory() : cacheSize(0) {} |
|
280 ~NetworkAccessManagerFactory() {} |
|
281 |
|
282 QNetworkAccessManager *create(QObject *parent); |
|
283 |
|
284 void setupProxy(QNetworkAccessManager *nam) |
|
285 { |
|
286 class SystemProxyFactory : public QNetworkProxyFactory |
|
287 { |
|
288 public: |
|
289 virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query) |
|
290 { |
|
291 QString protocolTag = query.protocolTag(); |
|
292 if (httpProxyInUse && (protocolTag == "http" || protocolTag == "https")) { |
|
293 QList<QNetworkProxy> ret; |
|
294 ret << httpProxy; |
|
295 return ret; |
|
296 } |
|
297 return QNetworkProxyFactory::systemProxyForQuery(query); |
|
298 } |
|
299 void setHttpProxy (QNetworkProxy proxy) |
|
300 { |
|
301 httpProxy = proxy; |
|
302 httpProxyInUse = true; |
|
303 } |
|
304 void unsetHttpProxy () |
|
305 { |
|
306 httpProxyInUse = false; |
|
307 } |
|
308 private: |
|
309 bool httpProxyInUse; |
|
310 QNetworkProxy httpProxy; |
|
311 }; |
|
312 |
|
313 SystemProxyFactory *proxyFactory = new SystemProxyFactory; |
|
314 if (ProxySettings::httpProxyInUse()) |
|
315 proxyFactory->setHttpProxy(ProxySettings::httpProxy()); |
|
316 else |
|
317 proxyFactory->unsetHttpProxy(); |
|
318 nam->setProxyFactory(proxyFactory); |
|
319 } |
|
320 |
|
321 void setCacheSize(int size) { |
|
322 if (size != cacheSize) { |
|
323 cacheSize = size; |
|
324 } |
|
325 } |
|
326 |
|
327 static PersistentCookieJar *cookieJar; |
|
328 QMutex mutex; |
|
329 int cacheSize; |
|
330 }; |
|
331 |
|
332 PersistentCookieJar *NetworkAccessManagerFactory::cookieJar = 0; |
|
333 |
|
334 static void cleanup_cookieJar() |
|
335 { |
|
336 delete NetworkAccessManagerFactory::cookieJar; |
|
337 NetworkAccessManagerFactory::cookieJar = 0; |
|
338 } |
|
339 |
|
340 QNetworkAccessManager *NetworkAccessManagerFactory::create(QObject *parent) |
|
341 { |
|
342 QMutexLocker lock(&mutex); |
|
343 QNetworkAccessManager *manager = new QNetworkAccessManager(parent); |
|
344 if (!cookieJar) { |
|
345 qAddPostRoutine(cleanup_cookieJar); |
|
346 cookieJar = new PersistentCookieJar(0); |
|
347 } |
|
348 manager->setCookieJar(cookieJar); |
|
349 cookieJar->setParent(0); |
|
350 setupProxy(manager); |
|
351 if (cacheSize > 0) { |
|
352 QNetworkDiskCache *cache = new QNetworkDiskCache; |
|
353 cache->setCacheDirectory(QDir::tempPath()+QLatin1String("/qml-viewer-network-cache")); |
|
354 cache->setMaximumCacheSize(cacheSize); |
|
355 manager->setCache(cache); |
|
356 } else { |
|
357 manager->setCache(0); |
|
358 } |
|
359 qDebug() << "created new network access manager for" << parent; |
|
360 return manager; |
|
361 } |
|
362 |
|
363 QString QDeclarativeViewer::getVideoFileName() |
|
364 { |
|
365 QString title = convertAvailable || ffmpegAvailable ? tr("Save Video File") : tr("Save PNG Frames"); |
|
366 QStringList types; |
|
367 if (ffmpegAvailable) types += tr("Common Video files")+QLatin1String(" (*.avi *.mpeg *.mov)"); |
|
368 if (convertAvailable) types += tr("GIF Animation")+QLatin1String(" (*.gif)"); |
|
369 types += tr("Individual PNG frames")+QLatin1String(" (*.png)"); |
|
370 if (ffmpegAvailable) types += tr("All ffmpeg formats (*.*)"); |
|
371 return QFileDialog::getSaveFileName(this, title, "", types.join(";; ")); |
|
372 } |
|
373 |
|
374 |
|
375 QDeclarativeViewer::QDeclarativeViewer(QWidget *parent, Qt::WindowFlags flags) |
|
376 #if defined(Q_OS_SYMBIAN) |
|
377 : QMainWindow(parent, flags) |
|
378 #else |
|
379 : QWidget(parent, flags) |
|
380 #endif |
|
381 , loggerWindow(new LoggerWidget()) |
|
382 , frame_stream(0), mb(0) |
|
383 , portraitOrientation(0), landscapeOrientation(0) |
|
384 , showWarningsWindow(0) |
|
385 , m_scriptOptions(0) |
|
386 , tester(0) |
|
387 , useQmlFileBrowser(true) |
|
388 , translator(0) |
|
389 { |
|
390 QDeclarativeViewer::registerTypes(); |
|
391 setWindowTitle(tr("Qt QML Viewer")); |
|
392 |
|
393 devicemode = false; |
|
394 canvas = 0; |
|
395 record_autotime = 0; |
|
396 record_rate = 50; |
|
397 record_args += QLatin1String("-sameq"); |
|
398 |
|
399 recdlg = new RecordingDialog(this); |
|
400 connect(recdlg->pickfile, SIGNAL(clicked()), this, SLOT(pickRecordingFile())); |
|
401 senseFfmpeg(); |
|
402 senseImageMagick(); |
|
403 if (!ffmpegAvailable) |
|
404 recdlg->ffmpegOptions->hide(); |
|
405 if (!ffmpegAvailable && !convertAvailable) |
|
406 recdlg->rateOptions->hide(); |
|
407 QString warn; |
|
408 if (!ffmpegAvailable) { |
|
409 if (!convertAvailable) |
|
410 warn = tr("ffmpeg and ImageMagick not available - no video output"); |
|
411 else |
|
412 warn = tr("ffmpeg not available - GIF and PNG outputs only"); |
|
413 recdlg->warning->setText(warn); |
|
414 } else { |
|
415 recdlg->warning->hide(); |
|
416 } |
|
417 |
|
418 canvas = new QDeclarativeView(this); |
|
419 |
|
420 canvas->setAttribute(Qt::WA_OpaquePaintEvent); |
|
421 canvas->setAttribute(Qt::WA_NoSystemBackground); |
|
422 |
|
423 canvas->setFocus(); |
|
424 |
|
425 QObject::connect(canvas, SIGNAL(sceneResized(QSize)), this, SLOT(sceneResized(QSize))); |
|
426 QObject::connect(canvas, SIGNAL(statusChanged(QDeclarativeView::Status)), this, SLOT(statusChanged())); |
|
427 QObject::connect(canvas->engine(), SIGNAL(quit()), QCoreApplication::instance (), SLOT(quit())); |
|
428 |
|
429 QObject::connect(warningsWidget(), SIGNAL(opened()), this, SLOT(warningsWidgetOpened())); |
|
430 QObject::connect(warningsWidget(), SIGNAL(closed()), this, SLOT(warningsWidgetClosed())); |
|
431 |
|
432 if (!(flags & Qt::FramelessWindowHint)) { |
|
433 createMenu(menuBar(),0); |
|
434 setPortrait(); |
|
435 } |
|
436 |
|
437 #if !defined(Q_OS_SYMBIAN) |
|
438 QVBoxLayout *layout = new QVBoxLayout; |
|
439 layout->setMargin(0); |
|
440 layout->setSpacing(0); |
|
441 setLayout(layout); |
|
442 if (mb) |
|
443 layout->addWidget(mb); |
|
444 layout->addWidget(canvas); |
|
445 #else |
|
446 setCentralWidget(canvas); |
|
447 #endif |
|
448 namFactory = new NetworkAccessManagerFactory; |
|
449 canvas->engine()->setNetworkAccessManagerFactory(namFactory); |
|
450 |
|
451 connect(&autoStartTimer, SIGNAL(triggered()), this, SLOT(autoStartRecording())); |
|
452 connect(&autoStopTimer, SIGNAL(triggered()), this, SLOT(autoStopRecording())); |
|
453 connect(&recordTimer, SIGNAL(triggered()), this, SLOT(recordFrame())); |
|
454 connect(DeviceOrientation::instance(), SIGNAL(orientationChanged()), |
|
455 this, SLOT(orientationChanged()), Qt::QueuedConnection); |
|
456 autoStartTimer.setRunning(false); |
|
457 autoStopTimer.setRunning(false); |
|
458 recordTimer.setRunning(false); |
|
459 recordTimer.setRepeating(true); |
|
460 } |
|
461 |
|
462 QDeclarativeViewer::~QDeclarativeViewer() |
|
463 { |
|
464 delete loggerWindow; |
|
465 canvas->engine()->setNetworkAccessManagerFactory(0); |
|
466 delete namFactory; |
|
467 } |
|
468 |
|
469 void QDeclarativeViewer::enableExperimentalGestures() |
|
470 { |
|
471 canvas->viewport()->grabGesture(Qt::TapGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent); |
|
472 canvas->viewport()->grabGesture(Qt::TapAndHoldGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent); |
|
473 canvas->viewport()->grabGesture(Qt::PanGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent); |
|
474 canvas->viewport()->grabGesture(Qt::PinchGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent); |
|
475 canvas->viewport()->grabGesture(Qt::SwipeGesture,Qt::DontStartGestureOnChildren|Qt::ReceivePartialGestures|Qt::IgnoredGesturesPropagateToParent); |
|
476 canvas->viewport()->setAttribute(Qt::WA_AcceptTouchEvents); |
|
477 } |
|
478 |
|
479 int QDeclarativeViewer::menuBarHeight() const |
|
480 { |
|
481 if (!(windowFlags() & Qt::FramelessWindowHint)) |
|
482 return menuBar()->height(); |
|
483 else |
|
484 return 0; // don't create menu |
|
485 } |
|
486 |
|
487 QMenuBar *QDeclarativeViewer::menuBar() const |
|
488 { |
|
489 #if !defined(Q_OS_SYMBIAN) |
|
490 if (!mb) |
|
491 mb = new SizedMenuBar((QWidget*)this, canvas); |
|
492 #else |
|
493 mb = QMainWindow::menuBar(); |
|
494 #endif |
|
495 |
|
496 return mb; |
|
497 } |
|
498 |
|
499 QDeclarativeView *QDeclarativeViewer::view() const |
|
500 { |
|
501 return canvas; |
|
502 } |
|
503 |
|
504 LoggerWidget *QDeclarativeViewer::warningsWidget() const |
|
505 { |
|
506 return loggerWindow; |
|
507 } |
|
508 |
|
509 void QDeclarativeViewer::createMenu(QMenuBar *menu, QMenu *flatmenu) |
|
510 { |
|
511 QObject *parent = flatmenu ? (QObject*)flatmenu : (QObject*)menu; |
|
512 |
|
513 QMenu *fileMenu = flatmenu ? flatmenu : menu->addMenu(tr("&File")); |
|
514 |
|
515 QAction *openAction = new QAction(tr("&Open..."), parent); |
|
516 openAction->setShortcut(QKeySequence("Ctrl+O")); |
|
517 connect(openAction, SIGNAL(triggered()), this, SLOT(openFile())); |
|
518 fileMenu->addAction(openAction); |
|
519 |
|
520 QAction *reloadAction = new QAction(tr("&Reload"), parent); |
|
521 reloadAction->setShortcut(QKeySequence("Ctrl+R")); |
|
522 connect(reloadAction, SIGNAL(triggered()), this, SLOT(reload())); |
|
523 fileMenu->addAction(reloadAction); |
|
524 |
|
525 #if defined(Q_OS_SYMBIAN) |
|
526 QAction *networkAction = new QAction(tr("Start &Network"), parent); |
|
527 connect(networkAction, SIGNAL(triggered()), this, SLOT(startNetwork())); |
|
528 fileMenu->addAction(networkAction); |
|
529 #endif |
|
530 |
|
531 #if !defined(Q_OS_SYMBIAN) |
|
532 if (flatmenu) flatmenu->addSeparator(); |
|
533 |
|
534 QMenu *recordMenu = flatmenu ? flatmenu : menu->addMenu(tr("&Recording")); |
|
535 |
|
536 QAction *snapshotAction = new QAction(tr("&Take Snapshot\tF3"), parent); |
|
537 connect(snapshotAction, SIGNAL(triggered()), this, SLOT(takeSnapShot())); |
|
538 recordMenu->addAction(snapshotAction); |
|
539 |
|
540 recordAction = new QAction(tr("Start Recording &Video\tF9"), parent); |
|
541 connect(recordAction, SIGNAL(triggered()), this, SLOT(toggleRecordingWithSelection())); |
|
542 recordMenu->addAction(recordAction); |
|
543 |
|
544 QAction *recordOptions = new QAction(tr("Video &Options..."), parent); |
|
545 connect(recordOptions, SIGNAL(triggered()), this, SLOT(chooseRecordingOptions())); |
|
546 |
|
547 if (flatmenu) |
|
548 flatmenu->addAction(recordOptions); |
|
549 |
|
550 if (flatmenu) flatmenu->addSeparator(); |
|
551 |
|
552 QMenu *debugMenu = flatmenu ? flatmenu->addMenu(tr("&Debugging")) : menu->addMenu(tr("&Debugging")); |
|
553 |
|
554 QAction *slowAction = new QAction(tr("&Slow Down Animations"), parent); |
|
555 slowAction->setShortcut(QKeySequence("Ctrl+.")); |
|
556 slowAction->setCheckable(true); |
|
557 connect(slowAction, SIGNAL(triggered(bool)), this, SLOT(setSlowMode(bool))); |
|
558 debugMenu->addAction(slowAction); |
|
559 |
|
560 showWarningsWindow = new QAction(tr("Show Warnings"), parent); |
|
561 showWarningsWindow->setCheckable((true)); |
|
562 showWarningsWindow->setChecked(loggerWindow->isVisible()); |
|
563 connect(showWarningsWindow, SIGNAL(triggered(bool)), this, SLOT(showWarnings(bool))); |
|
564 |
|
565 #if !defined(Q_OS_SYMBIAN) |
|
566 debugMenu->addAction(showWarningsWindow); |
|
567 #endif |
|
568 |
|
569 if (flatmenu) flatmenu->addSeparator(); |
|
570 |
|
571 #endif // Q_OS_SYMBIAN |
|
572 |
|
573 QMenu *settingsMenu = flatmenu ? flatmenu : menu->addMenu(tr("S&ettings")); |
|
574 QAction *proxyAction = new QAction(tr("Http &proxy..."), parent); |
|
575 connect(proxyAction, SIGNAL(triggered()), this, SLOT(showProxySettings())); |
|
576 settingsMenu->addAction(proxyAction); |
|
577 #if !defined(Q_OS_SYMBIAN) |
|
578 if (!flatmenu) |
|
579 settingsMenu->addAction(recordOptions); |
|
580 |
|
581 settingsMenu->addMenu(loggerWindow->preferencesMenu()); |
|
582 #else |
|
583 QAction *fullscreenAction = new QAction(tr("Full Screen"), parent); |
|
584 fullscreenAction->setCheckable(true); |
|
585 connect(fullscreenAction, SIGNAL(triggered()), this, SLOT(toggleFullScreen())); |
|
586 settingsMenu->addAction(fullscreenAction); |
|
587 #endif |
|
588 |
|
589 if (flatmenu) flatmenu->addSeparator(); |
|
590 |
|
591 QMenu *propertiesMenu = settingsMenu->addMenu(tr("Properties")); |
|
592 |
|
593 QActionGroup *orientation = new QActionGroup(parent); |
|
594 |
|
595 QAction *toggleOrientation = new QAction(tr("&Toggle Orientation"), parent); |
|
596 toggleOrientation->setCheckable(true); |
|
597 toggleOrientation->setShortcut(QKeySequence("Ctrl+T")); |
|
598 settingsMenu->addAction(toggleOrientation); |
|
599 connect(toggleOrientation, SIGNAL(triggered()), this, SLOT(toggleOrientation())); |
|
600 |
|
601 orientation->setExclusive(true); |
|
602 portraitOrientation = new QAction(tr("orientation: Portrait"), parent); |
|
603 portraitOrientation->setCheckable(true); |
|
604 connect(portraitOrientation, SIGNAL(triggered()), this, SLOT(setPortrait())); |
|
605 orientation->addAction(portraitOrientation); |
|
606 propertiesMenu->addAction(portraitOrientation); |
|
607 |
|
608 landscapeOrientation = new QAction(tr("orientation: Landscape"), parent); |
|
609 landscapeOrientation->setCheckable(true); |
|
610 connect(landscapeOrientation, SIGNAL(triggered()), this, SLOT(setLandscape())); |
|
611 orientation->addAction(landscapeOrientation); |
|
612 propertiesMenu->addAction(landscapeOrientation); |
|
613 |
|
614 if (flatmenu) flatmenu->addSeparator(); |
|
615 |
|
616 QMenu *helpMenu = flatmenu ? flatmenu : menu->addMenu(tr("&Help")); |
|
617 QAction *aboutAction = new QAction(tr("&About Qt..."), parent); |
|
618 connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); |
|
619 helpMenu->addAction(aboutAction); |
|
620 |
|
621 QAction *quitAction = new QAction(tr("&Quit"), parent); |
|
622 quitAction->setShortcut(QKeySequence("Ctrl+Q")); |
|
623 connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); |
|
624 fileMenu->addSeparator(); |
|
625 fileMenu->addAction(quitAction); |
|
626 if (menu) { |
|
627 menu->setFixedHeight(menu->sizeHint().height()); |
|
628 menu->setMinimumWidth(10); |
|
629 } |
|
630 } |
|
631 |
|
632 void QDeclarativeViewer::showProxySettings() |
|
633 { |
|
634 ProxySettings settingsDlg (this); |
|
635 |
|
636 connect (&settingsDlg, SIGNAL (accepted()), this, SLOT (proxySettingsChanged ())); |
|
637 |
|
638 settingsDlg.exec(); |
|
639 } |
|
640 |
|
641 void QDeclarativeViewer::proxySettingsChanged() |
|
642 { |
|
643 reload (); |
|
644 } |
|
645 |
|
646 void QDeclarativeViewer::setPortrait() |
|
647 { |
|
648 DeviceOrientation::instance()->setOrientation(DeviceOrientation::Portrait); |
|
649 portraitOrientation->setChecked(true); |
|
650 } |
|
651 |
|
652 void QDeclarativeViewer::setLandscape() |
|
653 { |
|
654 DeviceOrientation::instance()->setOrientation(DeviceOrientation::Landscape); |
|
655 landscapeOrientation->setChecked(true); |
|
656 } |
|
657 |
|
658 void QDeclarativeViewer::toggleOrientation() |
|
659 { |
|
660 DeviceOrientation::instance()->setOrientation(DeviceOrientation::instance()->orientation()==DeviceOrientation::Portrait?DeviceOrientation::Landscape:DeviceOrientation::Portrait); |
|
661 } |
|
662 |
|
663 void QDeclarativeViewer::toggleFullScreen() |
|
664 { |
|
665 if (isFullScreen()) |
|
666 showMaximized(); |
|
667 else |
|
668 showFullScreen(); |
|
669 } |
|
670 |
|
671 void QDeclarativeViewer::showWarnings(bool show) |
|
672 { |
|
673 loggerWindow->setVisible(show); |
|
674 } |
|
675 |
|
676 void QDeclarativeViewer::warningsWidgetOpened() |
|
677 { |
|
678 showWarningsWindow->setChecked(true); |
|
679 } |
|
680 |
|
681 void QDeclarativeViewer::warningsWidgetClosed() |
|
682 { |
|
683 showWarningsWindow->setChecked(false); |
|
684 } |
|
685 |
|
686 void QDeclarativeViewer::takeSnapShot() |
|
687 { |
|
688 static int snapshotcount = 1; |
|
689 QString snapFileName = QString(QLatin1String("snapshot%1.png")).arg(snapshotcount); |
|
690 QPixmap::grabWidget(canvas).save(snapFileName); |
|
691 qDebug() << "Wrote" << snapFileName; |
|
692 ++snapshotcount; |
|
693 } |
|
694 |
|
695 void QDeclarativeViewer::pickRecordingFile() |
|
696 { |
|
697 QString fileName = getVideoFileName(); |
|
698 if (!fileName.isEmpty()) |
|
699 recdlg->file->setText(fileName); |
|
700 } |
|
701 |
|
702 void QDeclarativeViewer::chooseRecordingOptions() |
|
703 { |
|
704 // File |
|
705 recdlg->file->setText(record_file); |
|
706 |
|
707 // Size |
|
708 recdlg->sizeOriginal->setText(tr("Original (%1x%2)").arg(canvas->width()).arg(canvas->height())); |
|
709 if (recdlg->sizeWidth->value()<=1) { |
|
710 recdlg->sizeWidth->setValue(canvas->width()); |
|
711 recdlg->sizeHeight->setValue(canvas->height()); |
|
712 } |
|
713 |
|
714 // Rate |
|
715 if (record_rate == 24) |
|
716 recdlg->hz24->setChecked(true); |
|
717 else if (record_rate == 25) |
|
718 recdlg->hz25->setChecked(true); |
|
719 else if (record_rate == 50) |
|
720 recdlg->hz50->setChecked(true); |
|
721 else if (record_rate == 60) |
|
722 recdlg->hz60->setChecked(true); |
|
723 else { |
|
724 recdlg->hzCustom->setChecked(true); |
|
725 recdlg->hz->setText(QString::number(record_rate)); |
|
726 } |
|
727 |
|
728 // Profile |
|
729 recdlg->setArguments(record_args.join(" ")); |
|
730 if (recdlg->exec()) { |
|
731 // File |
|
732 record_file = recdlg->file->text(); |
|
733 // Size |
|
734 if (recdlg->sizeOriginal->isChecked()) |
|
735 record_outsize = QSize(); |
|
736 else if (recdlg->size720p->isChecked()) |
|
737 record_outsize = QSize(1280,720); |
|
738 else if (recdlg->sizeVGA->isChecked()) |
|
739 record_outsize = QSize(640,480); |
|
740 else if (recdlg->sizeQVGA->isChecked()) |
|
741 record_outsize = QSize(320,240); |
|
742 else |
|
743 record_outsize = QSize(recdlg->sizeWidth->value(),recdlg->sizeHeight->value()); |
|
744 // Rate |
|
745 if (recdlg->hz24->isChecked()) |
|
746 record_rate = 24; |
|
747 else if (recdlg->hz25->isChecked()) |
|
748 record_rate = 25; |
|
749 else if (recdlg->hz50->isChecked()) |
|
750 record_rate = 50; |
|
751 else if (recdlg->hz60->isChecked()) |
|
752 record_rate = 60; |
|
753 else { |
|
754 record_rate = recdlg->hz->text().toDouble(); |
|
755 } |
|
756 // Profile |
|
757 record_args = recdlg->arguments().split(" ",QString::SkipEmptyParts); |
|
758 } |
|
759 } |
|
760 |
|
761 void QDeclarativeViewer::toggleRecordingWithSelection() |
|
762 { |
|
763 if (!recordTimer.isRunning()) { |
|
764 if (record_file.isEmpty()) { |
|
765 QString fileName = getVideoFileName(); |
|
766 if (fileName.isEmpty()) |
|
767 return; |
|
768 if (!fileName.contains(QRegExp(".[^\\/]*$"))) |
|
769 fileName += ".avi"; |
|
770 setRecordFile(fileName); |
|
771 } |
|
772 } |
|
773 toggleRecording(); |
|
774 } |
|
775 |
|
776 void QDeclarativeViewer::toggleRecording() |
|
777 { |
|
778 if (record_file.isEmpty()) { |
|
779 toggleRecordingWithSelection(); |
|
780 return; |
|
781 } |
|
782 bool recording = !recordTimer.isRunning(); |
|
783 recordAction->setText(recording ? tr("&Stop Recording Video\tF9") : tr("&Start Recording Video\tF9")); |
|
784 setRecording(recording); |
|
785 } |
|
786 |
|
787 void QDeclarativeViewer::setSlowMode(bool enable) |
|
788 { |
|
789 QUnifiedTimer::instance()->setSlowModeEnabled(enable); |
|
790 } |
|
791 |
|
792 void QDeclarativeViewer::addLibraryPath(const QString& lib) |
|
793 { |
|
794 canvas->engine()->addImportPath(lib); |
|
795 } |
|
796 |
|
797 void QDeclarativeViewer::addPluginPath(const QString& plugin) |
|
798 { |
|
799 canvas->engine()->addPluginPath(plugin); |
|
800 } |
|
801 |
|
802 void QDeclarativeViewer::reload() |
|
803 { |
|
804 open(currentFileOrUrl); |
|
805 } |
|
806 |
|
807 void QDeclarativeViewer::openFile() |
|
808 { |
|
809 QString cur = canvas->source().toLocalFile(); |
|
810 if (useQmlFileBrowser) { |
|
811 open("qrc:/content/Browser.qml"); |
|
812 } else { |
|
813 QString fileName = QFileDialog::getOpenFileName(this, tr("Open QML file"), cur, tr("QML Files (*.qml)")); |
|
814 if (!fileName.isEmpty()) { |
|
815 QFileInfo fi(fileName); |
|
816 open(fi.absoluteFilePath()); |
|
817 } |
|
818 } |
|
819 } |
|
820 |
|
821 void QDeclarativeViewer::statusChanged() |
|
822 { |
|
823 if (canvas->status() == QDeclarativeView::Error && tester) |
|
824 tester->executefailure(); |
|
825 |
|
826 if (canvas->status() == QDeclarativeView::Ready) { |
|
827 initialSize = canvas->sizeHint(); |
|
828 if (canvas->resizeMode() == QDeclarativeView::SizeRootObjectToView) { |
|
829 updateSizeHints(); |
|
830 resize(QSize(initialSize.width(), initialSize.height()+menuBarHeight())); |
|
831 } |
|
832 } |
|
833 } |
|
834 |
|
835 void QDeclarativeViewer::launch(const QString& file_or_url) |
|
836 { |
|
837 QMetaObject::invokeMethod(this, "open", Qt::QueuedConnection, Q_ARG(QString, file_or_url)); |
|
838 } |
|
839 |
|
840 void QDeclarativeViewer::loadTranslationFile(const QString& directory) |
|
841 { |
|
842 if (!translator) { |
|
843 translator = new QTranslator(this); |
|
844 QApplication::installTranslator(translator); |
|
845 } |
|
846 |
|
847 translator->load(QLatin1String("qml_" )+QLocale::system().name(), directory + QLatin1String("/i18n")); |
|
848 } |
|
849 |
|
850 void QDeclarativeViewer::loadDummyDataFiles(const QString& directory) |
|
851 { |
|
852 QDir dir(directory+"/dummydata", "*.qml"); |
|
853 QStringList list = dir.entryList(); |
|
854 for (int i = 0; i < list.size(); ++i) { |
|
855 QString qml = list.at(i); |
|
856 QFile f(dir.filePath(qml)); |
|
857 f.open(QIODevice::ReadOnly); |
|
858 QByteArray data = f.readAll(); |
|
859 QDeclarativeComponent comp(canvas->engine()); |
|
860 comp.setData(data, QUrl()); |
|
861 QObject *dummyData = comp.create(); |
|
862 |
|
863 if(comp.isError()) { |
|
864 QList<QDeclarativeError> errors = comp.errors(); |
|
865 foreach (const QDeclarativeError &error, errors) { |
|
866 qWarning() << error; |
|
867 } |
|
868 if (tester) tester->executefailure(); |
|
869 } |
|
870 |
|
871 if (dummyData) { |
|
872 qWarning() << "Loaded dummy data:" << dir.filePath(qml); |
|
873 qml.truncate(qml.length()-4); |
|
874 canvas->rootContext()->setContextProperty(qml, dummyData); |
|
875 dummyData->setParent(this); |
|
876 } |
|
877 } |
|
878 } |
|
879 |
|
880 bool QDeclarativeViewer::open(const QString& file_or_url) |
|
881 { |
|
882 currentFileOrUrl = file_or_url; |
|
883 |
|
884 QUrl url; |
|
885 QFileInfo fi(file_or_url); |
|
886 if (fi.exists()) |
|
887 url = QUrl::fromLocalFile(fi.absoluteFilePath()); |
|
888 else |
|
889 url = QUrl(file_or_url); |
|
890 setWindowTitle(tr("%1 - Qt QML Viewer").arg(file_or_url)); |
|
891 |
|
892 if (!m_script.isEmpty()) |
|
893 tester = new QDeclarativeTester(m_script, m_scriptOptions, canvas); |
|
894 |
|
895 delete canvas->rootObject(); |
|
896 canvas->engine()->clearComponentCache(); |
|
897 QDeclarativeContext *ctxt = canvas->rootContext(); |
|
898 ctxt->setContextProperty("qmlViewer", this); |
|
899 #ifdef Q_OS_SYMBIAN |
|
900 ctxt->setContextProperty("qmlViewerFolder", "E:\\"); // Documents on your S60 phone |
|
901 #else |
|
902 ctxt->setContextProperty("qmlViewerFolder", QDir::currentPath()); |
|
903 #endif |
|
904 |
|
905 ctxt->setContextProperty("runtime", Runtime::instance()); |
|
906 |
|
907 QString fileName = url.toLocalFile(); |
|
908 if (!fileName.isEmpty()) { |
|
909 fi.setFile(fileName); |
|
910 if (fi.exists()) { |
|
911 if (fi.suffix().toLower() != QLatin1String("qml")) { |
|
912 qWarning() << "qml cannot open non-QML file" << fileName; |
|
913 return false; |
|
914 } |
|
915 |
|
916 QFileInfo fi(fileName); |
|
917 loadTranslationFile(fi.path()); |
|
918 loadDummyDataFiles(fi.path()); |
|
919 } else { |
|
920 qWarning() << "qml cannot find file:" << fileName; |
|
921 return false; |
|
922 } |
|
923 } |
|
924 |
|
925 QTime t; |
|
926 t.start(); |
|
927 |
|
928 canvas->setSource(url); |
|
929 |
|
930 return true; |
|
931 } |
|
932 |
|
933 void QDeclarativeViewer::startNetwork() |
|
934 { |
|
935 #if defined(SYMBIAN_NETWORK_INIT) |
|
936 qt_SetDefaultIap(); |
|
937 #endif |
|
938 } |
|
939 |
|
940 void QDeclarativeViewer::setAutoRecord(int from, int to) |
|
941 { |
|
942 if (from==0) from=1; // ensure resized |
|
943 record_autotime = to-from; |
|
944 autoStartTimer.setInterval(from); |
|
945 autoStartTimer.setRunning(true); |
|
946 } |
|
947 |
|
948 void QDeclarativeViewer::setRecordArgs(const QStringList& a) |
|
949 { |
|
950 record_args = a; |
|
951 } |
|
952 |
|
953 void QDeclarativeViewer::setRecordFile(const QString& f) |
|
954 { |
|
955 record_file = f; |
|
956 } |
|
957 |
|
958 void QDeclarativeViewer::setRecordRate(int fps) |
|
959 { |
|
960 record_rate = fps; |
|
961 } |
|
962 |
|
963 void QDeclarativeViewer::sceneResized(QSize size) |
|
964 { |
|
965 if (size.width() > 0 && size.height() > 0) { |
|
966 if (canvas->resizeMode() == QDeclarativeView::SizeViewToRootObject) { |
|
967 updateSizeHints(); |
|
968 } |
|
969 } |
|
970 } |
|
971 |
|
972 void QDeclarativeViewer::keyPressEvent(QKeyEvent *event) |
|
973 { |
|
974 if (event->key() == Qt::Key_0 && devicemode) |
|
975 exit(0); |
|
976 else if (event->key() == Qt::Key_F1 || (event->key() == Qt::Key_1 && devicemode)) { |
|
977 qDebug() << "F1 - help\n" |
|
978 << "F2 - save test script\n" |
|
979 << "F3 - take PNG snapshot\n" |
|
980 << "F4 - show items and state\n" |
|
981 << "F5 - reload QML\n" |
|
982 << "F6 - show object tree\n" |
|
983 << "F7 - show timing\n" |
|
984 << "F9 - toggle video recording\n" |
|
985 << "F10 - toggle orientation\n" |
|
986 << "device keys: 0=quit, 1..8=F1..F8" |
|
987 ; |
|
988 } else if (event->key() == Qt::Key_F2 || (event->key() == Qt::Key_2 && devicemode)) { |
|
989 if (tester && m_scriptOptions & Record) |
|
990 tester->save(); |
|
991 } else if (event->key() == Qt::Key_F3 || (event->key() == Qt::Key_3 && devicemode)) { |
|
992 takeSnapShot(); |
|
993 } else if (event->key() == Qt::Key_F5 || (event->key() == Qt::Key_5 && devicemode)) { |
|
994 reload(); |
|
995 } else if (event->key() == Qt::Key_F9 || (event->key() == Qt::Key_9 && devicemode)) { |
|
996 toggleRecording(); |
|
997 } else if (event->key() == Qt::Key_F10) { |
|
998 if (portraitOrientation) { |
|
999 if (portraitOrientation->isChecked()) |
|
1000 setLandscape(); |
|
1001 else |
|
1002 setPortrait(); |
|
1003 } |
|
1004 } |
|
1005 |
|
1006 QWidget::keyPressEvent(event); |
|
1007 } |
|
1008 |
|
1009 bool QDeclarativeViewer::event(QEvent *event) |
|
1010 { |
|
1011 if (event->type() == QEvent::WindowActivate) { |
|
1012 Runtime::instance()->setActiveWindow(true); |
|
1013 } else if (event->type() == QEvent::WindowDeactivate) { |
|
1014 Runtime::instance()->setActiveWindow(false); |
|
1015 } |
|
1016 return QWidget::event(event); |
|
1017 } |
|
1018 |
|
1019 void QDeclarativeViewer::senseImageMagick() |
|
1020 { |
|
1021 QProcess proc; |
|
1022 proc.start("convert", QStringList() << "-h"); |
|
1023 proc.waitForFinished(2000); |
|
1024 QString help = proc.readAllStandardOutput(); |
|
1025 convertAvailable = help.contains("ImageMagick"); |
|
1026 } |
|
1027 |
|
1028 void QDeclarativeViewer::senseFfmpeg() |
|
1029 { |
|
1030 QProcess proc; |
|
1031 proc.start("ffmpeg", QStringList() << "-h"); |
|
1032 proc.waitForFinished(2000); |
|
1033 QString ffmpegHelp = proc.readAllStandardOutput(); |
|
1034 ffmpegAvailable = ffmpegHelp.contains("-s "); |
|
1035 ffmpegHelp = tr("Video recording uses ffmpeg:")+"\n\n"+ffmpegHelp; |
|
1036 |
|
1037 QDialog *d = new QDialog(recdlg); |
|
1038 QVBoxLayout *l = new QVBoxLayout(d); |
|
1039 QTextBrowser *b = new QTextBrowser(d); |
|
1040 QFont f = b->font(); |
|
1041 f.setFamily("courier"); |
|
1042 b->setFont(f); |
|
1043 b->setText(ffmpegHelp); |
|
1044 l->addWidget(b); |
|
1045 d->setLayout(l); |
|
1046 ffmpegHelpWindow = d; |
|
1047 connect(recdlg->ffmpegHelp,SIGNAL(clicked()), ffmpegHelpWindow, SLOT(show())); |
|
1048 } |
|
1049 |
|
1050 void QDeclarativeViewer::setRecording(bool on) |
|
1051 { |
|
1052 if (on == recordTimer.isRunning()) |
|
1053 return; |
|
1054 |
|
1055 int period = int(1000/record_rate+0.5); |
|
1056 QUnifiedTimer::instance()->setTimingInterval(on ? period:16); |
|
1057 QUnifiedTimer::instance()->setConsistentTiming(on); |
|
1058 if (on) { |
|
1059 canvas->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); |
|
1060 recordTimer.setInterval(period); |
|
1061 recordTimer.setRunning(true); |
|
1062 frame_fmt = record_file.right(4).toLower(); |
|
1063 frame = QImage(canvas->width(),canvas->height(),QImage::Format_RGB32); |
|
1064 if (frame_fmt != ".png" && (!convertAvailable || frame_fmt != ".gif")) { |
|
1065 // Stream video to ffmpeg |
|
1066 |
|
1067 QProcess *proc = new QProcess(this); |
|
1068 connect(proc, SIGNAL(finished(int)), this, SLOT(ffmpegFinished(int))); |
|
1069 frame_stream = proc; |
|
1070 |
|
1071 QStringList args; |
|
1072 args << "-y"; |
|
1073 args << "-r" << QString::number(record_rate); |
|
1074 args << "-f" << "rawvideo"; |
|
1075 args << "-pix_fmt" << (frame_fmt == ".gif" ? "rgb24" : "rgb32"); |
|
1076 args << "-s" << QString("%1x%2").arg(canvas->width()).arg(canvas->height()); |
|
1077 args << "-i" << "-"; |
|
1078 if (record_outsize.isValid()) { |
|
1079 args << "-s" << QString("%1x%2").arg(record_outsize.width()).arg(record_outsize.height()); |
|
1080 args << "-aspect" << QString::number(double(canvas->width())/canvas->height()); |
|
1081 } |
|
1082 args += record_args; |
|
1083 args << record_file; |
|
1084 proc->start("ffmpeg",args); |
|
1085 |
|
1086 } else { |
|
1087 // Store frames, save to GIF/PNG |
|
1088 frame_stream = 0; |
|
1089 } |
|
1090 } else { |
|
1091 canvas->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate); |
|
1092 recordTimer.setRunning(false); |
|
1093 if (frame_stream) { |
|
1094 qDebug() << "Saving video..."; |
|
1095 frame_stream->close(); |
|
1096 qDebug() << "Wrote" << record_file; |
|
1097 } else { |
|
1098 QProgressDialog progress(tr("Saving frames..."), tr("Cancel"), 0, frames.count()+10, this); |
|
1099 progress.setWindowModality(Qt::WindowModal); |
|
1100 |
|
1101 int frame=0; |
|
1102 QStringList inputs; |
|
1103 qDebug() << "Saving frames..."; |
|
1104 |
|
1105 QString framename; |
|
1106 bool png_output = false; |
|
1107 if (record_file.right(4).toLower()==".png") { |
|
1108 if (record_file.contains('%')) |
|
1109 framename = record_file; |
|
1110 else |
|
1111 framename = record_file.left(record_file.length()-4)+"%04d"+record_file.right(4); |
|
1112 png_output = true; |
|
1113 } else { |
|
1114 framename = "tmp-frame%04d.png"; |
|
1115 png_output = false; |
|
1116 } |
|
1117 foreach (QImage* img, frames) { |
|
1118 progress.setValue(progress.value()+1); |
|
1119 if (progress.wasCanceled()) |
|
1120 break; |
|
1121 QString name; |
|
1122 name.sprintf(framename.toLocal8Bit(),frame++); |
|
1123 if (record_outsize.isValid()) |
|
1124 *img = img->scaled(record_outsize,Qt::IgnoreAspectRatio,Qt::SmoothTransformation); |
|
1125 if (record_dither=="ordered") |
|
1126 img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::OrderedDither).save(name); |
|
1127 else if (record_dither=="threshold") |
|
1128 img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither|Qt::ThresholdDither).save(name); |
|
1129 else if (record_dither=="floyd") |
|
1130 img->convertToFormat(QImage::Format_Indexed8,Qt::PreferDither).save(name); |
|
1131 else |
|
1132 img->save(name); |
|
1133 inputs << name; |
|
1134 delete img; |
|
1135 } |
|
1136 |
|
1137 if (!progress.wasCanceled()) { |
|
1138 if (png_output) { |
|
1139 framename.replace(QRegExp("%\\d*."),"*"); |
|
1140 qDebug() << "Wrote frames" << framename; |
|
1141 inputs.clear(); // don't remove them |
|
1142 } else { |
|
1143 // ImageMagick and gifsicle for GIF encoding |
|
1144 progress.setLabelText(tr("Converting frames to GIF file...")); |
|
1145 QStringList args; |
|
1146 args << "-delay" << QString::number(period/10); |
|
1147 args << inputs; |
|
1148 args << record_file; |
|
1149 qDebug() << "Converting..." << record_file << "(this may take a while)"; |
|
1150 if (0!=QProcess::execute("convert", args)) { |
|
1151 qWarning() << "Cannot run ImageMagick 'convert' - recorded frames not converted"; |
|
1152 inputs.clear(); // don't remove them |
|
1153 qDebug() << "Wrote frames tmp-frame*.png"; |
|
1154 } else { |
|
1155 if (record_file.right(4).toLower() == ".gif") { |
|
1156 qDebug() << "Compressing..." << record_file; |
|
1157 if (0!=QProcess::execute("gifsicle", QStringList() << "-O2" << "-o" << record_file << record_file)) |
|
1158 qWarning() << "Cannot run 'gifsicle' - not compressed"; |
|
1159 } |
|
1160 qDebug() << "Wrote" << record_file; |
|
1161 } |
|
1162 } |
|
1163 } |
|
1164 |
|
1165 progress.setValue(progress.maximum()-1); |
|
1166 foreach (QString name, inputs) |
|
1167 QFile::remove(name); |
|
1168 |
|
1169 frames.clear(); |
|
1170 } |
|
1171 } |
|
1172 qDebug() << "Recording: " << (recordTimer.isRunning()?"ON":"OFF"); |
|
1173 } |
|
1174 |
|
1175 void QDeclarativeViewer::ffmpegFinished(int code) |
|
1176 { |
|
1177 qDebug() << "ffmpeg returned" << code << frame_stream->readAllStandardError(); |
|
1178 } |
|
1179 |
|
1180 void QDeclarativeViewer::autoStartRecording() |
|
1181 { |
|
1182 setRecording(true); |
|
1183 autoStopTimer.setInterval(record_autotime); |
|
1184 autoStopTimer.setRunning(true); |
|
1185 } |
|
1186 |
|
1187 void QDeclarativeViewer::autoStopRecording() |
|
1188 { |
|
1189 setRecording(false); |
|
1190 } |
|
1191 |
|
1192 void QDeclarativeViewer::recordFrame() |
|
1193 { |
|
1194 canvas->QWidget::render(&frame); |
|
1195 if (frame_stream) { |
|
1196 if (frame_fmt == ".gif") { |
|
1197 // ffmpeg can't do 32bpp with gif |
|
1198 QImage rgb24 = frame.convertToFormat(QImage::Format_RGB888); |
|
1199 frame_stream->write((char*)rgb24.bits(),rgb24.numBytes()); |
|
1200 } else { |
|
1201 frame_stream->write((char*)frame.bits(),frame.numBytes()); |
|
1202 } |
|
1203 } else { |
|
1204 frames.append(new QImage(frame)); |
|
1205 } |
|
1206 } |
|
1207 |
|
1208 void QDeclarativeViewer::orientationChanged() |
|
1209 { |
|
1210 if (canvas->resizeMode() == QDeclarativeView::SizeRootObjectToView) { |
|
1211 if (canvas->rootObject()) { |
|
1212 QSizeF rootObjectSize = canvas->rootObject()->boundingRect().size(); |
|
1213 QSize newSize(rootObjectSize.width(), rootObjectSize.height()+menuBarHeight()); |
|
1214 if (size() != newSize) { |
|
1215 resize(newSize); |
|
1216 } |
|
1217 } |
|
1218 } |
|
1219 } |
|
1220 |
|
1221 void QDeclarativeViewer::setDeviceKeys(bool on) |
|
1222 { |
|
1223 devicemode = on; |
|
1224 } |
|
1225 |
|
1226 void QDeclarativeViewer::setNetworkCacheSize(int size) |
|
1227 { |
|
1228 namFactory->setCacheSize(size); |
|
1229 } |
|
1230 |
|
1231 void QDeclarativeViewer::setUseGL(bool useGL) |
|
1232 { |
|
1233 #ifdef GL_SUPPORTED |
|
1234 if (useGL) { |
|
1235 QGLFormat format = QGLFormat::defaultFormat(); |
|
1236 #ifdef Q_WS_MAC |
|
1237 format.setSampleBuffers(true); |
|
1238 #else |
|
1239 format.setSampleBuffers(false); |
|
1240 #endif |
|
1241 |
|
1242 QGLWidget *glWidget = new QGLWidget(format); |
|
1243 //### potentially faster, but causes junk to appear if top-level is Item, not Rectangle |
|
1244 //glWidget->setAutoFillBackground(false); |
|
1245 |
|
1246 canvas->setViewport(glWidget); |
|
1247 } |
|
1248 #endif |
|
1249 } |
|
1250 |
|
1251 void QDeclarativeViewer::setUseNativeFileBrowser(bool use) |
|
1252 { |
|
1253 useQmlFileBrowser = !use; |
|
1254 } |
|
1255 |
|
1256 void QDeclarativeViewer::setSizeToView(bool sizeToView) |
|
1257 { |
|
1258 QDeclarativeView::ResizeMode resizeMode = sizeToView ? QDeclarativeView::SizeRootObjectToView : QDeclarativeView::SizeViewToRootObject; |
|
1259 if (resizeMode != canvas->resizeMode()) { |
|
1260 canvas->setResizeMode(resizeMode); |
|
1261 updateSizeHints(); |
|
1262 } |
|
1263 } |
|
1264 |
|
1265 void QDeclarativeViewer::updateSizeHints() |
|
1266 { |
|
1267 if (canvas->resizeMode() == QDeclarativeView::SizeViewToRootObject) { |
|
1268 QSize newWindowSize = canvas->sizeHint(); |
|
1269 newWindowSize.setHeight(newWindowSize.height()+menuBarHeight()); |
|
1270 if (!isFullScreen() && !isMaximized()) { |
|
1271 resize(newWindowSize); |
|
1272 setFixedSize(newWindowSize); |
|
1273 } |
|
1274 } else { // QDeclarativeView::SizeRootObjectToView |
|
1275 canvas->setMinimumSize(QSize(0,0)); |
|
1276 canvas->setMaximumSize(QSize(16777215,16777215)); |
|
1277 setMinimumSize(QSize(0,0)); |
|
1278 setMaximumSize(QSize(16777215,16777215)); |
|
1279 } |
|
1280 updateGeometry(); |
|
1281 } |
|
1282 |
|
1283 void QDeclarativeViewer::registerTypes() |
|
1284 { |
|
1285 static bool registered = false; |
|
1286 |
|
1287 if (!registered) { |
|
1288 // registering only for exposing the DeviceOrientation::Orientation enum |
|
1289 qmlRegisterUncreatableType<DeviceOrientation>("Qt",4,7,"Orientation",""); |
|
1290 registered = true; |
|
1291 } |
|
1292 } |
|
1293 |
|
1294 QT_END_NAMESPACE |
|
1295 |
|
1296 #include "qmlruntime.moc" |