2 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
3 * Copyright (C) 2011 University of Szeged
4 * Copyright (C) 2011 Kristof Kosztyo <Kosztyo.Kristof@stud.u-szeged.hu>
5 * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
6 * Copyright (C) 2006 George Staikos <staikos@kde.org>
7 * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
8 * Copyright (C) 2006 Zack Rusin <zack@kde.org>
9 * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
11 * All rights reserved.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
22 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
23 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
30 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include "launcherwindow.h"
38 #include "cookiejar.h"
39 #include "urlloader.h"
41 #include <QApplication>
44 #include <QCoreApplication>
45 #include <QDialogButtonBox>
46 #include <QInputDialog>
48 #ifndef QT_NO_LINEEDIT
51 #ifndef QT_NO_SHORTCUT
57 #include <QToolButton>
59 #include <QVBoxLayout>
61 #if !defined(QT_NO_FILEDIALOG) && !defined(QT_NO_MESSAGEBOX)
62 #include <QFileDialog>
64 #include <QMessageBox>
65 #include <QNetworkReply>
68 #if !defined(QT_NO_NETWORKDISKCACHE) && !defined(QT_NO_DESKTOPSERVICES)
70 #include <QStandardPaths>
72 #include <QDesktopServices>
74 #include <QtNetwork/QNetworkDiskCache>
77 const int gExitClickArea = 80;
78 QVector<int> LauncherWindow::m_zoomLevels;
80 static TestBrowserCookieJar* testBrowserCookieJarInstance()
82 static TestBrowserCookieJar* cookieJar = new TestBrowserCookieJar(qApp);
86 LauncherWindow::LauncherWindow(WindowOptions* data, QGraphicsScene* sharedScene)
92 , m_formatMenuAction(0)
94 #if !defined(QT_NO_FILEDIALOG) && !defined(QT_NO_MESSAGEBOX)
97 #ifndef QT_NO_LINEEDIT
102 m_windowOptions = *data;
105 if (sharedScene && data->useGraphicsView)
106 static_cast<QGraphicsView*>(m_view)->setScene(sharedScene);
109 #if !defined(QT_NO_FILEDIALOG) && !defined(QT_NO_MESSAGEBOX)
110 connect(page(), SIGNAL(downloadRequested(const QNetworkRequest&)), this, SLOT(downloadRequest(const QNetworkRequest&)));
114 LauncherWindow::~LauncherWindow()
119 void LauncherWindow::init()
121 QSplitter* splitter = new QSplitter(Qt::Vertical, this);
122 setCentralWidget(splitter);
124 if (m_windowOptions.startMaximized)
125 setWindowState(windowState() | Qt::WindowMaximized);
129 m_inspector = new WebInspector;
130 #ifndef QT_NO_PROPERTIES
131 if (!m_windowOptions.inspectorUrl.isEmpty())
132 m_inspector->setProperty("_q_inspectorUrl", m_windowOptions.inspectorUrl);
134 connect(this, SIGNAL(destroyed()), m_inspector, SLOT(deleteLater()));
136 // the zoom values are chosen to be like in Mozilla Firefox 3
137 if (!m_zoomLevels.count()) {
138 m_zoomLevels << 30 << 50 << 67 << 80 << 90;
140 m_zoomLevels << 110 << 120 << 133 << 150 << 170 << 200 << 240 << 300;
146 void LauncherWindow::initializeView()
150 m_inputUrl = addressUrl();
151 QUrl url = page()->mainFrame()->url();
152 setPage(new WebPage(this));
153 setDiskCache(m_windowOptions.useDiskCache);
154 setUseDiskCookies(m_windowOptions.useDiskCookies);
156 // We reuse the same cookieJar on multiple QNAMs, which is OK.
157 QObject* cookieJarParent = testBrowserCookieJarInstance()->parent();
158 page()->networkAccessManager()->setCookieJar(testBrowserCookieJarInstance());
159 testBrowserCookieJarInstance()->setParent(cookieJarParent);
161 QSplitter* splitter = static_cast<QSplitter*>(centralWidget());
163 if (!m_windowOptions.useGraphicsView) {
164 WebViewTraditional* view = new WebViewTraditional(splitter);
165 view->setPage(page());
167 view->installEventFilter(this);
171 WebViewGraphicsBased* view = new WebViewGraphicsBased(splitter);
174 toggleQGLWidgetViewport(m_windowOptions.useQGLWidgetViewport);
176 view->setPage(page());
178 connect(view, SIGNAL(currentFPSUpdated(int)), this, SLOT(updateFPS(int)));
180 view->installEventFilter(this);
181 // The implementation of QAbstractScrollArea::eventFilter makes us need
182 // to install the event filter also on the viewport of a QGraphicsView.
183 view->viewport()->installEventFilter(this);
186 m_touchMocking = false;
188 connect(page(), SIGNAL(loadStarted()), this, SLOT(loadStarted()));
189 connect(page(), SIGNAL(loadFinished(bool)), this, SLOT(loadFinished()));
190 connect(page(), SIGNAL(linkHovered(const QString&, const QString&, const QString&)),
191 this, SLOT(showLinkHover(const QString&, const QString&)));
192 connect(this, SIGNAL(enteredFullScreenMode(bool)), this, SLOT(toggleFullScreenMode(bool)));
194 if (m_windowOptions.printLoadedUrls)
195 connect(page()->mainFrame(), SIGNAL(urlChanged(QUrl)), this, SLOT(printURL(QUrl)));
199 splitter->addWidget(m_inspector);
200 m_inspector->setPage(page());
203 if (m_windowOptions.remoteInspectorPort)
204 page()->setProperty("_q_webInspectorServerPort", m_windowOptions.remoteInspectorPort);
207 page()->mainFrame()->load(url);
209 setAddressUrl(m_inputUrl);
210 m_inputUrl = QString();
214 void LauncherWindow::applyPrefs()
216 QWebSettings* settings = page()->settings();
217 settings->setAttribute(QWebSettings::AcceleratedCompositingEnabled, m_windowOptions.useCompositing);
218 settings->setAttribute(QWebSettings::TiledBackingStoreEnabled, m_windowOptions.useTiledBackingStore);
219 settings->setAttribute(QWebSettings::FrameFlatteningEnabled, m_windowOptions.useFrameFlattening);
220 settings->setAttribute(QWebSettings::WebGLEnabled, m_windowOptions.useWebGL);
222 if (!isGraphicsBased())
225 WebViewGraphicsBased* view = static_cast<WebViewGraphicsBased*>(m_view);
226 view->setViewportUpdateMode(m_windowOptions.viewportUpdateMode);
227 view->setFrameRateMeasurementEnabled(m_windowOptions.showFrameRate);
228 view->setItemCacheMode(m_windowOptions.cacheWebView ? QGraphicsItem::DeviceCoordinateCache : QGraphicsItem::NoCache);
230 if (m_windowOptions.resizesToContents)
231 toggleResizesToContents(m_windowOptions.resizesToContents);
234 void LauncherWindow::createChrome()
236 #ifndef QT_NO_SHORTCUT
237 QMenu* fileMenu = menuBar()->addMenu("&File");
238 fileMenu->addAction("New Window", this, SLOT(newWindow()), QKeySequence::New);
239 fileMenu->addAction(tr("Open File..."), this, SLOT(openFile()), QKeySequence::Open);
240 fileMenu->addAction(tr("Open Location..."), this, SLOT(openLocation()), QKeySequence(Qt::CTRL | Qt::Key_L));
241 fileMenu->addAction("Close Window", this, SLOT(close()), QKeySequence::Close);
242 fileMenu->addSeparator();
243 fileMenu->addAction("Take Screen Shot...", this, SLOT(screenshot()));
244 #ifndef QT_NO_PRINTER
245 fileMenu->addAction(tr("Print..."), this, SLOT(print()), QKeySequence::Print);
247 fileMenu->addSeparator();
248 fileMenu->addAction("Quit", QApplication::instance(), SLOT(closeAllWindows()), QKeySequence(Qt::CTRL | Qt::Key_Q));
250 QMenu* editMenu = menuBar()->addMenu("&Edit");
251 editMenu->addAction(page()->action(QWebPage::Undo));
252 editMenu->addAction(page()->action(QWebPage::Redo));
253 editMenu->addSeparator();
254 editMenu->addAction(page()->action(QWebPage::Cut));
255 editMenu->addAction(page()->action(QWebPage::Copy));
256 editMenu->addAction(page()->action(QWebPage::Paste));
257 editMenu->addSeparator();
258 #ifndef QT_NO_LINEEDIT
259 editMenu->addAction("&Find", this, SLOT(showFindBar()), QKeySequence(Qt::CTRL | Qt::Key_F));
260 editMenu->addSeparator();
262 QAction* setEditable = editMenu->addAction("Set Editable", this, SLOT(setEditable(bool)));
263 setEditable->setCheckable(true);
265 editMenu->addAction("Clear Cookies", this, SLOT(clearCookies()));
267 QMenu* viewMenu = menuBar()->addMenu("&View");
268 viewMenu->addAction(page()->action(QWebPage::Stop));
269 viewMenu->addAction(page()->action(QWebPage::Reload));
270 viewMenu->addSeparator();
271 QAction* zoomIn = viewMenu->addAction("Zoom &In", this, SLOT(zoomIn()));
272 QAction* zoomOut = viewMenu->addAction("Zoom &Out", this, SLOT(zoomOut()));
273 QAction* resetZoom = viewMenu->addAction("Reset Zoom", this, SLOT(resetZoom()));
274 QAction* zoomTextOnly = viewMenu->addAction("Zoom Text Only", this, SLOT(toggleZoomTextOnly(bool)));
275 zoomTextOnly->setCheckable(true);
276 zoomTextOnly->setChecked(false);
277 viewMenu->addSeparator();
278 viewMenu->addAction("Dump HTML", this, SLOT(dumpHtml()));
279 // viewMenu->addAction("Dump plugins", this, SLOT(dumpPlugins()));
281 zoomIn->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus));
282 zoomOut->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Minus));
283 resetZoom->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0));
285 QMenu* formatMenu = new QMenu("F&ormat", this);
286 m_formatMenuAction = menuBar()->addMenu(formatMenu);
287 m_formatMenuAction->setVisible(false);
288 formatMenu->addAction(page()->action(QWebPage::ToggleBold));
289 formatMenu->addAction(page()->action(QWebPage::ToggleItalic));
290 formatMenu->addAction(page()->action(QWebPage::ToggleUnderline));
291 QMenu* writingMenu = formatMenu->addMenu(tr("Writing Direction"));
292 writingMenu->addAction(page()->action(QWebPage::SetTextDirectionDefault));
293 writingMenu->addAction(page()->action(QWebPage::SetTextDirectionLeftToRight));
294 writingMenu->addAction(page()->action(QWebPage::SetTextDirectionRightToLeft));
296 QMenu* windowMenu = menuBar()->addMenu("&Window");
297 QAction* toggleFullScreen = windowMenu->addAction("Toggle FullScreen", this, SIGNAL(enteredFullScreenMode(bool)));
298 toggleFullScreen->setShortcut(Qt::Key_F11);
299 toggleFullScreen->setCheckable(true);
300 toggleFullScreen->setChecked(false);
301 // When exit fullscreen mode by clicking on the exit area (bottom right corner) we must
302 // uncheck the Toggle FullScreen action.
303 toggleFullScreen->connect(this, SIGNAL(enteredFullScreenMode(bool)), SLOT(setChecked(bool)));
305 QWebSettings* settings = page()->settings();
307 QMenu* toolsMenu = menuBar()->addMenu("&Develop");
308 QMenu* graphicsViewMenu = toolsMenu->addMenu("QGraphicsView");
309 QAction* toggleGraphicsView = graphicsViewMenu->addAction("Toggle use of QGraphicsView", this, SLOT(toggleWebView(bool)));
310 toggleGraphicsView->setCheckable(true);
311 toggleGraphicsView->setChecked(isGraphicsBased());
313 QAction* toggleWebGL = toolsMenu->addAction("Toggle WebGL", this, SLOT(toggleWebGL(bool)));
314 toggleWebGL->setCheckable(true);
315 toggleWebGL->setChecked(settings->testAttribute(QWebSettings::WebGLEnabled));
317 QAction* spatialNavigationAction = toolsMenu->addAction("Toggle Spatial Navigation", this, SLOT(toggleSpatialNavigation(bool)));
318 spatialNavigationAction->setCheckable(true);
319 spatialNavigationAction->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_S));
321 QAction* toggleFrameFlattening = toolsMenu->addAction("Toggle Frame Flattening", this, SLOT(toggleFrameFlattening(bool)));
322 toggleFrameFlattening->setCheckable(true);
323 toggleFrameFlattening->setChecked(settings->testAttribute(QWebSettings::FrameFlatteningEnabled));
325 QAction* touchMockAction = toolsMenu->addAction("Toggle touch mocking", this, SLOT(setTouchMocking(bool)));
326 touchMockAction->setCheckable(true);
327 touchMockAction->setShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_T));
329 toolsMenu->addSeparator();
331 QAction* toggleLocalStorage = toolsMenu->addAction("Enable Local Storage", this, SLOT(toggleLocalStorage(bool)));
332 toggleLocalStorage->setCheckable(true);
333 toggleLocalStorage->setChecked(m_windowOptions.useLocalStorage);
335 QAction* toggleOfflineStorageDatabase = toolsMenu->addAction("Enable Offline Storage Database", this, SLOT(toggleOfflineStorageDatabase(bool)));
336 toggleOfflineStorageDatabase->setCheckable(true);
337 toggleOfflineStorageDatabase->setChecked(m_windowOptions.useOfflineStorageDatabase);
339 QAction* toggleOfflineWebApplicationCache = toolsMenu->addAction("Enable Offline Web Application Cache", this, SLOT(toggleOfflineWebApplicationCache(bool)));
340 toggleOfflineWebApplicationCache->setCheckable(true);
341 toggleOfflineWebApplicationCache->setChecked(m_windowOptions.useOfflineWebApplicationCache);
343 QAction* offlineStorageDefaultQuotaAction = toolsMenu->addAction("Set Offline Storage Default Quota Size", this, SLOT(setOfflineStorageDefaultQuota()));
344 offlineStorageDefaultQuotaAction->setCheckable(true);
345 offlineStorageDefaultQuotaAction->setChecked(m_windowOptions.offlineStorageDefaultQuotaSize);
347 toolsMenu->addSeparator();
349 QAction* userAgentAction = toolsMenu->addAction("Change User Agent", this, SLOT(showUserAgentDialog()));
350 userAgentAction->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_U));
352 toolsMenu->addAction("Select Elements...", this, SLOT(selectElements()));
354 QAction* showInspectorAction = toolsMenu->addAction("Show Web Inspector", m_inspector, SLOT(setVisible(bool)), QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_I));
355 showInspectorAction->setCheckable(true);
356 showInspectorAction->connect(m_inspector, SIGNAL(visibleChanged(bool)), SLOT(setChecked(bool)));
357 toolsMenu->addSeparator();
358 toolsMenu->addAction("Load URLs from file", this, SLOT(loadURLListFromFile()));
360 // GraphicsView sub menu.
361 QAction* toggleAcceleratedCompositing = graphicsViewMenu->addAction("Toggle Accelerated Compositing", this, SLOT(toggleAcceleratedCompositing(bool)));
362 toggleAcceleratedCompositing->setCheckable(true);
363 toggleAcceleratedCompositing->setChecked(settings->testAttribute(QWebSettings::AcceleratedCompositingEnabled));
364 toggleAcceleratedCompositing->setEnabled(isGraphicsBased());
365 toggleAcceleratedCompositing->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
367 QAction* toggleResizesToContents = graphicsViewMenu->addAction("Toggle Resizes To Contents Mode", this, SLOT(toggleResizesToContents(bool)));
368 toggleResizesToContents->setCheckable(true);
369 toggleResizesToContents->setChecked(m_windowOptions.resizesToContents);
370 toggleResizesToContents->setEnabled(isGraphicsBased());
371 toggleResizesToContents->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
373 QAction* toggleTiledBackingStore = graphicsViewMenu->addAction("Toggle Tiled Backing Store", this, SLOT(toggleTiledBackingStore(bool)));
374 toggleTiledBackingStore->setCheckable(true);
375 toggleTiledBackingStore->setChecked(m_windowOptions.useTiledBackingStore);
376 toggleTiledBackingStore->setEnabled(isGraphicsBased());
377 toggleTiledBackingStore->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
380 QAction* toggleQGLWidgetViewport = graphicsViewMenu->addAction("Toggle use of QGLWidget Viewport", this, SLOT(toggleQGLWidgetViewport(bool)));
381 toggleQGLWidgetViewport->setCheckable(true);
382 toggleQGLWidgetViewport->setChecked(m_windowOptions.useQGLWidgetViewport);
383 toggleQGLWidgetViewport->setEnabled(isGraphicsBased());
384 toggleQGLWidgetViewport->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
387 QMenu* viewportUpdateMenu = graphicsViewMenu->addMenu("Change Viewport Update Mode");
388 viewportUpdateMenu->setEnabled(isGraphicsBased());
389 viewportUpdateMenu->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
391 QAction* fullUpdate = viewportUpdateMenu->addAction("FullViewportUpdate");
392 fullUpdate->setCheckable(true);
393 fullUpdate->setChecked((m_windowOptions.viewportUpdateMode == QGraphicsView::FullViewportUpdate) ? true : false);
395 QAction* minimalUpdate = viewportUpdateMenu->addAction("MinimalViewportUpdate");
396 minimalUpdate->setCheckable(true);
397 minimalUpdate->setChecked((m_windowOptions.viewportUpdateMode == QGraphicsView::MinimalViewportUpdate) ? true : false);
399 QAction* smartUpdate = viewportUpdateMenu->addAction("SmartViewportUpdate");
400 smartUpdate->setCheckable(true);
401 smartUpdate->setChecked((m_windowOptions.viewportUpdateMode == QGraphicsView::SmartViewportUpdate) ? true : false);
403 QAction* boundingRectUpdate = viewportUpdateMenu->addAction("BoundingRectViewportUpdate");
404 boundingRectUpdate->setCheckable(true);
405 boundingRectUpdate->setChecked((m_windowOptions.viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate) ? true : false);
407 QAction* noUpdate = viewportUpdateMenu->addAction("NoViewportUpdate");
408 noUpdate->setCheckable(true);
409 noUpdate->setChecked((m_windowOptions.viewportUpdateMode == QGraphicsView::NoViewportUpdate) ? true : false);
411 QSignalMapper* signalMapper = new QSignalMapper(viewportUpdateMenu);
412 signalMapper->setMapping(fullUpdate, QGraphicsView::FullViewportUpdate);
413 signalMapper->setMapping(minimalUpdate, QGraphicsView::MinimalViewportUpdate);
414 signalMapper->setMapping(smartUpdate, QGraphicsView::SmartViewportUpdate);
415 signalMapper->setMapping(boundingRectUpdate, QGraphicsView::BoundingRectViewportUpdate);
416 signalMapper->setMapping(noUpdate, QGraphicsView::NoViewportUpdate);
418 connect(fullUpdate, SIGNAL(triggered()), signalMapper, SLOT(map()));
419 connect(minimalUpdate, SIGNAL(triggered()), signalMapper, SLOT(map()));
420 connect(smartUpdate, SIGNAL(triggered()), signalMapper, SLOT(map()));
421 connect(boundingRectUpdate, SIGNAL(triggered()), signalMapper, SLOT(map()));
422 connect(noUpdate, SIGNAL(triggered()), signalMapper, SLOT(map()));
424 connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(changeViewportUpdateMode(int)));
426 QActionGroup* viewportUpdateModeActions = new QActionGroup(viewportUpdateMenu);
427 viewportUpdateModeActions->addAction(fullUpdate);
428 viewportUpdateModeActions->addAction(minimalUpdate);
429 viewportUpdateModeActions->addAction(smartUpdate);
430 viewportUpdateModeActions->addAction(boundingRectUpdate);
431 viewportUpdateModeActions->addAction(noUpdate);
433 graphicsViewMenu->addSeparator();
435 QAction* flipAnimated = graphicsViewMenu->addAction("Animated Flip");
436 flipAnimated->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
437 flipAnimated->setEnabled(isGraphicsBased());
438 connect(flipAnimated, SIGNAL(triggered()), SLOT(animatedFlip()));
440 QAction* flipYAnimated = graphicsViewMenu->addAction("Animated Y-Flip");
441 flipYAnimated->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
442 flipYAnimated->setEnabled(isGraphicsBased());
443 connect(flipYAnimated, SIGNAL(triggered()), SLOT(animatedYFlip()));
445 QAction* cloneWindow = graphicsViewMenu->addAction("Clone Window", this, SLOT(cloneWindow()));
446 cloneWindow->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
447 cloneWindow->setEnabled(isGraphicsBased());
449 graphicsViewMenu->addSeparator();
451 QAction* showFPS = graphicsViewMenu->addAction("Show FPS", this, SLOT(showFPS(bool)));
452 showFPS->setCheckable(true);
453 showFPS->setEnabled(isGraphicsBased());
454 showFPS->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
455 showFPS->setChecked(m_windowOptions.showFrameRate);
457 QMenu* settingsMenu = menuBar()->addMenu("&Settings");
459 #if !defined(QT_NO_NETWORKDISKCACHE) && !defined(QT_NO_DESKTOPSERVICES)
460 QAction* toggleDiskCache = settingsMenu->addAction("Use Disk Cache", this, SLOT(setDiskCache(bool)));
461 toggleDiskCache->setCheckable(true);
462 toggleDiskCache->setChecked(m_windowOptions.useDiskCache);
465 QAction* toggleAutoLoadImages = settingsMenu->addAction("Disable Auto Load Images", this, SLOT(toggleAutoLoadImages(bool)));
466 toggleAutoLoadImages->setCheckable(true);
467 toggleAutoLoadImages->setChecked(false);
469 QAction* togglePlugins = settingsMenu->addAction("Disable Plugins", this, SLOT(togglePlugins(bool)));
470 togglePlugins->setCheckable(true);
471 togglePlugins->setChecked(false);
473 QAction* toggleInterruptingJavaScripteEnabled = settingsMenu->addAction("Enable interrupting js scripts", this, SLOT(toggleInterruptingJavaScriptEnabled(bool)));
474 toggleInterruptingJavaScripteEnabled->setCheckable(true);
475 toggleInterruptingJavaScripteEnabled->setChecked(false);
477 QAction* toggleJavascriptCanOpenWindows = settingsMenu->addAction("Enable js popup windows", this, SLOT(toggleJavascriptCanOpenWindows(bool)));
478 toggleJavascriptCanOpenWindows->setCheckable(true);
479 toggleJavascriptCanOpenWindows->setChecked(false);
481 QAction* toggleUseDiskCookies = settingsMenu->addAction("Save Cookies on Disk", this, SLOT(setUseDiskCookies(bool)));
482 toggleUseDiskCookies->setCheckable(true);
483 toggleUseDiskCookies->setChecked(m_windowOptions.useDiskCookies);
485 #ifndef QT_NO_LINEEDIT
486 m_findBar = new QToolBar("Find", this);
487 addToolBar(Qt::BottomToolBarArea, m_findBar);
489 QToolButton* findClose = new QToolButton(m_findBar);
490 findClose->setText("X");
491 m_lineEdit = new QLineEdit(m_findBar);
492 m_lineEdit->setMaximumWidth(200);
493 QToolButton* findPrevious = new QToolButton(m_findBar);
494 findPrevious->setArrowType(Qt::LeftArrow);
495 QToolButton* findNext = new QToolButton(m_findBar);
496 findNext->setArrowType(Qt::RightArrow);
497 QCheckBox* findCaseSensitive = new QCheckBox("Case Sensitive", m_findBar);
498 QCheckBox* findWrapAround = new QCheckBox("Wrap Around", m_findBar);
499 QCheckBox* findHighLightAll = new QCheckBox("HighLight All", m_findBar);
501 QSignalMapper* findSignalMapper = new QSignalMapper(m_findBar);
502 findSignalMapper->setMapping(m_lineEdit, s_findNormalFlag);
503 findSignalMapper->setMapping(findPrevious, QWebPage::FindBackward);
504 findSignalMapper->setMapping(findNext, s_findNormalFlag);
505 findSignalMapper->setMapping(findCaseSensitive, QWebPage::FindCaseSensitively);
506 findSignalMapper->setMapping(findWrapAround, QWebPage::FindWrapsAroundDocument);
507 findSignalMapper->setMapping(findHighLightAll, QWebPage::HighlightAllOccurrences);
509 connect(findClose, SIGNAL(clicked()), this, SLOT(showFindBar()));
510 connect(m_lineEdit, SIGNAL(textChanged(const QString &)), findSignalMapper, SLOT(map()));
511 connect(findPrevious, SIGNAL(pressed()), findSignalMapper, SLOT(map()));
512 connect(findNext, SIGNAL(pressed()), findSignalMapper, SLOT(map()));
513 connect(findCaseSensitive, SIGNAL(stateChanged(int)), findSignalMapper, SLOT(map()));
514 connect(findWrapAround, SIGNAL(stateChanged(int)), findSignalMapper, SLOT(map()));
515 connect(findHighLightAll, SIGNAL(stateChanged(int)), findSignalMapper, SLOT(map()));
517 connect(findSignalMapper, SIGNAL(mapped(int)), this, SLOT(find(int)));
519 m_findBar->addWidget(findClose);
520 m_findBar->addWidget(m_lineEdit);
521 m_findBar->addWidget(findPrevious);
522 m_findBar->addWidget(findNext);
523 m_findBar->addWidget(findCaseSensitive);
524 m_findBar->addWidget(findWrapAround);
525 m_findBar->addWidget(findHighLightAll);
526 m_findBar->setMovable(false);
527 m_findBar->setVisible(false);
532 bool LauncherWindow::isGraphicsBased() const
534 return bool(qobject_cast<QGraphicsView*>(m_view));
537 void LauncherWindow::sendTouchEvent()
539 if (m_touchPoints.isEmpty())
542 QEvent::Type type = QEvent::TouchUpdate;
543 if (m_touchPoints.size() == 1) {
544 if (m_touchPoints[0].state() == Qt::TouchPointReleased)
545 type = QEvent::TouchEnd;
546 else if (m_touchPoints[0].state() == Qt::TouchPointPressed)
547 type = QEvent::TouchBegin;
550 QTouchEvent touchEv(type);
551 touchEv.setTouchPoints(m_touchPoints);
552 QCoreApplication::sendEvent(page(), &touchEv);
554 // After sending the event, remove all touchpoints that were released
555 if (m_touchPoints[0].state() == Qt::TouchPointReleased)
556 m_touchPoints.removeAt(0);
557 if (m_touchPoints.size() > 1 && m_touchPoints[1].state() == Qt::TouchPointReleased)
558 m_touchPoints.removeAt(1);
561 bool LauncherWindow::eventFilter(QObject* obj, QEvent* event)
563 // If click pos is the bottom right corner (square with size defined by gExitClickArea)
564 // and the window is on FullScreen, the window must return to its original state.
565 if (event->type() == QEvent::MouseButtonRelease) {
566 QMouseEvent* ev = static_cast<QMouseEvent*>(event);
567 if (windowState() == Qt::WindowFullScreen
568 && ev->pos().x() > (width() - gExitClickArea)
569 && ev->pos().y() > (height() - gExitClickArea)) {
571 emit enteredFullScreenMode(false);
576 return QObject::eventFilter(obj, event);
578 if (event->type() == QEvent::MouseButtonPress
579 || event->type() == QEvent::MouseButtonRelease
580 || event->type() == QEvent::MouseButtonDblClick
581 || event->type() == QEvent::MouseMove) {
583 QMouseEvent* ev = static_cast<QMouseEvent*>(event);
584 if (ev->type() == QEvent::MouseMove
585 && !(ev->buttons() & Qt::LeftButton))
588 QTouchEvent::TouchPoint touchPoint;
589 touchPoint.setState(Qt::TouchPointMoved);
590 if ((ev->type() == QEvent::MouseButtonPress
591 || ev->type() == QEvent::MouseButtonDblClick))
592 touchPoint.setState(Qt::TouchPointPressed);
593 else if (ev->type() == QEvent::MouseButtonRelease)
594 touchPoint.setState(Qt::TouchPointReleased);
597 touchPoint.setScreenPos(ev->globalPos());
598 touchPoint.setPos(ev->pos());
599 touchPoint.setPressure(1);
601 // If the point already exists, update it. Otherwise create it.
602 if (m_touchPoints.size() > 0 && !m_touchPoints[0].id())
603 m_touchPoints[0] = touchPoint;
604 else if (m_touchPoints.size() > 1 && !m_touchPoints[1].id())
605 m_touchPoints[1] = touchPoint;
607 m_touchPoints.append(touchPoint);
610 } else if (event->type() == QEvent::KeyPress
611 && static_cast<QKeyEvent*>(event)->key() == Qt::Key_F
612 && static_cast<QKeyEvent*>(event)->modifiers() == Qt::ControlModifier) {
614 // If the keyboard point is already pressed, release it.
615 // Otherwise create it and append to m_touchPoints.
616 if (m_touchPoints.size() > 0 && m_touchPoints[0].id() == 1) {
617 m_touchPoints[0].setState(Qt::TouchPointReleased);
619 } else if (m_touchPoints.size() > 1 && m_touchPoints[1].id() == 1) {
620 m_touchPoints[1].setState(Qt::TouchPointReleased);
623 QTouchEvent::TouchPoint touchPoint;
624 touchPoint.setState(Qt::TouchPointPressed);
626 touchPoint.setScreenPos(QCursor::pos());
627 touchPoint.setPos(m_view->mapFromGlobal(QCursor::pos()));
628 touchPoint.setPressure(1);
629 m_touchPoints.append(touchPoint);
632 // After sending the event, change the touchpoint state to stationary
633 m_touchPoints.last().setState(Qt::TouchPointStationary);
640 void LauncherWindow::loadStarted()
642 m_view->setFocus(Qt::OtherFocusReason);
645 void LauncherWindow::loadFinished()
647 QUrl url = page()->mainFrame()->url();
648 addCompleterEntry(url);
649 if (m_inputUrl.isEmpty())
650 setAddressUrl(url.toString(QUrl::RemoveUserInfo));
652 setAddressUrl(m_inputUrl);
653 m_inputUrl = QString();
657 void LauncherWindow::showLinkHover(const QString &link, const QString &toolTip)
659 statusBar()->showMessage(link);
660 #ifndef QT_NO_TOOLTIP
661 if (!toolTip.isEmpty())
662 QToolTip::showText(QCursor::pos(), toolTip);
666 void LauncherWindow::zoomAnimationFinished()
668 if (!isGraphicsBased())
670 QGraphicsWebView* view = static_cast<WebViewGraphicsBased*>(m_view)->graphicsWebView();
671 view->setTiledBackingStoreFrozen(false);
674 void LauncherWindow::applyZoom()
676 #ifndef QT_NO_ANIMATION
677 if (isGraphicsBased() && page()->settings()->testAttribute(QWebSettings::TiledBackingStoreEnabled)) {
678 QGraphicsWebView* view = static_cast<WebViewGraphicsBased*>(m_view)->graphicsWebView();
679 view->setTiledBackingStoreFrozen(true);
680 if (!m_zoomAnimation) {
681 m_zoomAnimation = new QPropertyAnimation(view, "scale");
682 m_zoomAnimation->setStartValue(view->scale());
683 connect(m_zoomAnimation, SIGNAL(finished()), this, SLOT(zoomAnimationFinished()));
685 m_zoomAnimation->stop();
686 m_zoomAnimation->setStartValue(m_zoomAnimation->currentValue());
689 m_zoomAnimation->setDuration(300);
690 m_zoomAnimation->setEndValue(qreal(m_currentZoom) / 100.);
691 m_zoomAnimation->start();
695 page()->mainFrame()->setZoomFactor(qreal(m_currentZoom) / 100.0);
698 void LauncherWindow::zoomIn()
700 int i = m_zoomLevels.indexOf(m_currentZoom);
702 if (i < m_zoomLevels.count() - 1)
703 m_currentZoom = m_zoomLevels[i + 1];
708 void LauncherWindow::zoomOut()
710 int i = m_zoomLevels.indexOf(m_currentZoom);
713 m_currentZoom = m_zoomLevels[i - 1];
718 void LauncherWindow::resetZoom()
724 void LauncherWindow::toggleZoomTextOnly(bool b)
726 page()->settings()->setAttribute(QWebSettings::ZoomTextOnly, b);
729 void LauncherWindow::print()
731 #if !defined(QT_NO_PRINTER)
732 QPrintPreviewDialog dlg(this);
733 connect(&dlg, SIGNAL(paintRequested(QPrinter*)),
734 page()->mainFrame(), SLOT(print(QPrinter*)));
739 void LauncherWindow::screenshot()
741 QPixmap pixmap = QPixmap::grabWidget(m_view);
744 label->setAttribute(Qt::WA_DeleteOnClose);
745 label->setWindowTitle("Screenshot - Preview");
746 label->setPixmap(pixmap);
749 #ifndef QT_NO_FILEDIALOG
750 QString fileName = QFileDialog::getSaveFileName(label, "Screenshot");
751 if (!fileName.isEmpty()) {
752 pixmap.save(fileName, "png");
754 label->setWindowTitle(QString("Screenshot - Saved at %1").arg(fileName));
759 toggleQGLWidgetViewport(m_windowOptions.useQGLWidgetViewport);
763 void LauncherWindow::setEditable(bool on)
765 page()->setContentEditable(on);
766 #ifndef QT_NO_SHORTCUT
767 m_formatMenuAction->setVisible(on);
772 void LauncherWindow::dumpPlugins() {
773 QList<QWebPluginInfo> plugins = QWebSettings::pluginDatabase()->plugins();
774 foreach (const QWebPluginInfo plugin, plugins) {
775 qDebug() << "Plugin:" << plugin.name();
776 foreach (const QWebPluginInfo::MimeType mime, plugin.mimeTypes()) {
777 qDebug() << " " << mime.name;
783 void LauncherWindow::dumpHtml()
785 qDebug() << "HTML: " << page()->mainFrame()->toHtml();
788 void LauncherWindow::selectElements()
790 #ifndef QT_NO_INPUTDIALOG
792 QString str = QInputDialog::getText(this, "Select elements", "Choose elements",
793 QLineEdit::Normal, "a", &ok);
795 if (ok && !str.isEmpty()) {
796 QWebElementCollection result = page()->mainFrame()->findAllElements(str);
797 foreach (QWebElement e, result)
798 e.setStyleProperty("background-color", "yellow");
799 statusBar()->showMessage(QString("%1 element(s) selected").arg(result.count()), 5000);
804 void LauncherWindow::setDiskCache(bool enable)
806 #if !defined(QT_NO_NETWORKDISKCACHE) && !defined(QT_NO_DESKTOPSERVICES)
807 m_windowOptions.useDiskCache = enable;
808 QNetworkDiskCache* cache = 0;
810 cache = new QNetworkDiskCache();
812 QString cacheLocation = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
814 QString cacheLocation = QDesktopServices::storageLocation(QDesktopServices::CacheLocation);
816 cache->setCacheDirectory(cacheLocation);
818 page()->networkAccessManager()->setCache(cache);
822 void LauncherWindow::setTouchMocking(bool on)
827 void LauncherWindow::toggleWebView(bool graphicsBased)
829 m_windowOptions.useGraphicsView = graphicsBased;
831 #ifndef QT_NO_SHORTCUT
837 void LauncherWindow::toggleAcceleratedCompositing(bool toggle)
839 m_windowOptions.useCompositing = toggle;
840 page()->settings()->setAttribute(QWebSettings::AcceleratedCompositingEnabled, toggle);
843 void LauncherWindow::toggleTiledBackingStore(bool toggle)
845 page()->settings()->setAttribute(QWebSettings::TiledBackingStoreEnabled, toggle);
848 void LauncherWindow::toggleResizesToContents(bool toggle)
850 m_windowOptions.resizesToContents = toggle;
851 static_cast<WebViewGraphicsBased*>(m_view)->setResizesToContents(toggle);
854 void LauncherWindow::toggleWebGL(bool toggle)
856 m_windowOptions.useWebGL = toggle;
857 page()->settings()->setAttribute(QWebSettings::WebGLEnabled, toggle);
860 void LauncherWindow::animatedFlip()
862 qobject_cast<WebViewGraphicsBased*>(m_view)->animatedFlip();
865 void LauncherWindow::animatedYFlip()
867 qobject_cast<WebViewGraphicsBased*>(m_view)->animatedYFlip();
869 void LauncherWindow::toggleSpatialNavigation(bool b)
871 page()->settings()->setAttribute(QWebSettings::SpatialNavigationEnabled, b);
874 void LauncherWindow::toggleFullScreenMode(bool enable)
876 bool alreadyEnabled = windowState() & Qt::WindowFullScreen;
877 if (enable ^ alreadyEnabled)
878 setWindowState(windowState() ^ Qt::WindowFullScreen);
881 void LauncherWindow::toggleFrameFlattening(bool toggle)
883 m_windowOptions.useFrameFlattening = toggle;
884 page()->settings()->setAttribute(QWebSettings::FrameFlatteningEnabled, toggle);
887 void LauncherWindow::toggleInterruptingJavaScriptEnabled(bool enable)
889 page()->setInterruptingJavaScriptEnabled(enable);
892 void LauncherWindow::toggleJavascriptCanOpenWindows(bool enable)
894 page()->settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, enable);
897 void LauncherWindow::setUseDiskCookies(bool enable)
899 testBrowserCookieJarInstance()->setDiskStorageEnabled(enable);
902 void LauncherWindow::clearCookies()
904 testBrowserCookieJarInstance()->reset();
907 void LauncherWindow::toggleAutoLoadImages(bool enable)
909 page()->settings()->setAttribute(QWebSettings::AutoLoadImages, !enable);
912 void LauncherWindow::togglePlugins(bool enable)
914 page()->settings()->setAttribute(QWebSettings::PluginsEnabled, !enable);
918 void LauncherWindow::toggleQGLWidgetViewport(bool enable)
920 if (!isGraphicsBased())
923 m_windowOptions.useQGLWidgetViewport = enable;
924 WebViewGraphicsBased* view = static_cast<WebViewGraphicsBased*>(m_view);
926 view->setViewport(enable ? new QGLWidget() : 0);
930 void LauncherWindow::changeViewportUpdateMode(int mode)
932 m_windowOptions.viewportUpdateMode = QGraphicsView::ViewportUpdateMode(mode);
934 if (!isGraphicsBased())
937 WebViewGraphicsBased* view = static_cast<WebViewGraphicsBased*>(m_view);
938 view->setViewportUpdateMode(m_windowOptions.viewportUpdateMode);
941 void LauncherWindow::showFPS(bool enable)
943 if (!isGraphicsBased())
946 m_windowOptions.showFrameRate = enable;
947 WebViewGraphicsBased* view = static_cast<WebViewGraphicsBased*>(m_view);
948 view->setFrameRateMeasurementEnabled(enable);
951 statusBar()->clearMessage();
954 void LauncherWindow::showUserAgentDialog()
957 QFile file(":/useragentlist.txt");
958 if (file.open(QIODevice::ReadOnly)) {
959 while (!file.atEnd())
960 items << file.readLine().trimmed();
965 QString customUserAgent = settings.value("CustomUserAgent").toString();
966 if (!items.contains(customUserAgent) && !customUserAgent.isEmpty())
967 items << customUserAgent;
969 QDialog* dialog = new QDialog(this);
970 dialog->resize(size().width() * 0.7, dialog->size().height());
971 dialog->setWindowTitle("Change User Agent");
973 QVBoxLayout* layout = new QVBoxLayout(dialog);
974 dialog->setLayout(layout);
976 #ifndef QT_NO_COMBOBOX
977 QComboBox* combo = new QComboBox(dialog);
978 combo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
979 combo->setEditable(true);
980 combo->insertItems(0, items);
981 layout->addWidget(combo);
983 int index = combo->findText(page()->userAgentForUrl(QUrl()));
984 combo->setCurrentIndex(index);
987 QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
988 | QDialogButtonBox::Cancel, Qt::Horizontal, dialog);
989 connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
990 connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject()));
991 layout->addWidget(buttonBox);
993 #ifndef QT_NO_COMBOBOX
994 if (dialog->exec() && !combo->currentText().isEmpty()) {
995 page()->setUserAgent(combo->currentText());
996 if (!items.contains(combo->currentText()))
997 settings.setValue("CustomUserAgent", combo->currentText());
1004 void LauncherWindow::loadURLListFromFile()
1006 QString selectedFile;
1007 #ifndef QT_NO_FILEDIALOG
1008 selectedFile = QFileDialog::getOpenFileName(this, tr("Load URL list from file")
1009 , QString(), tr("Text Files (*.txt);;All Files (*)"));
1011 if (selectedFile.isEmpty())
1014 m_urlLoader = new UrlLoader(this->page()->mainFrame(), selectedFile, 0, 0);
1015 m_urlLoader->loadNext();
1018 void LauncherWindow::printURL(const QUrl& url)
1020 QTextStream output(stdout);
1021 output << "Loaded: " << url.toString() << endl;
1024 #if !defined(QT_NO_FILEDIALOG) && !defined(QT_NO_MESSAGEBOX)
1025 void LauncherWindow::downloadRequest(const QNetworkRequest &request)
1027 QNetworkAccessManager* manager = new QNetworkAccessManager(this);
1028 m_reply = manager->get(request);
1029 connect(m_reply, SIGNAL(finished()), this, SLOT(fileDownloadFinished()));
1032 void LauncherWindow::fileDownloadFinished()
1034 QFileInfo fileInf(m_reply->request().url().toString());
1035 QString requestFileName = QDir::homePath() + "/" + fileInf.fileName();
1036 QString fileName = QFileDialog::getSaveFileName(this, "Save as...", requestFileName, "All Files (*)");
1038 if (fileName.isEmpty())
1040 if (m_reply->error() != QNetworkReply::NoError)
1041 QMessageBox::critical(this, QString("Download"), QString("Download failed."));
1043 QFile file(fileName);
1044 file.open(QIODevice::WriteOnly);
1045 file.write(m_reply->readAll());
1047 QMessageBox::information(this, QString("Download"), fileName + QString(" downloaded successfully."));
1052 void LauncherWindow::updateFPS(int fps)
1054 QString fpsStatusText = QString("Current FPS: %1").arg(fps);
1056 statusBar()->showMessage(fpsStatusText);
1059 void LauncherWindow::toggleLocalStorage(bool toggle)
1061 m_windowOptions.useLocalStorage = toggle;
1062 page()->settings()->setAttribute(QWebSettings::LocalStorageEnabled, toggle);
1065 void LauncherWindow::toggleOfflineStorageDatabase(bool toggle)
1067 m_windowOptions.useOfflineStorageDatabase = toggle;
1068 page()->settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, toggle);
1071 void LauncherWindow::toggleOfflineWebApplicationCache(bool toggle)
1073 m_windowOptions.useOfflineWebApplicationCache = toggle;
1074 page()->settings()->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, toggle);
1077 void LauncherWindow::setOfflineStorageDefaultQuota()
1079 // For command line execution, quota size is taken from command line.
1080 if (m_windowOptions.offlineStorageDefaultQuotaSize)
1081 page()->settings()->setOfflineStorageDefaultQuota(m_windowOptions.offlineStorageDefaultQuotaSize);
1083 #ifndef QT_NO_INPUTDIALOG
1085 // Maximum size is set to 25 * 1024 * 1024.
1086 int quotaSize = QInputDialog::getInt(this, "Offline Storage Default Quota Size" , "Quota Size", 0, 0, 26214400, 1, &ok);
1088 page()->settings()->setOfflineStorageDefaultQuota(quotaSize);
1093 LauncherWindow* LauncherWindow::newWindow()
1095 LauncherWindow* mw = new LauncherWindow(&m_windowOptions);
1100 LauncherWindow* LauncherWindow::cloneWindow()
1102 LauncherWindow* mw = new LauncherWindow(&m_windowOptions, qobject_cast<QGraphicsView*>(m_view)->scene());
1107 #ifndef QT_NO_LINEEDIT
1108 void LauncherWindow::showFindBar()
1110 if (!m_findBar->isVisible()) {
1111 m_findBar->setVisible(true);
1112 m_lineEdit->setText(page()->selectedText());
1113 m_lineEdit->setFocus(Qt::PopupFocusReason);
1115 m_findBar->setVisible(false);
1116 page()->findText("", QWebPage::HighlightAllOccurrences);
1120 void LauncherWindow::find(int mode = s_findNormalFlag)
1124 palette.setColor(m_lineEdit->backgroundRole(), Qt::white);
1125 page()->findText("", QFlag(QWebPage::HighlightAllOccurrences));
1127 m_findFlag = m_findFlag ^ mode;
1128 if (mode == s_findNormalFlag || mode == QWebPage::FindBackward) {
1129 found = page()->findText(m_lineEdit->text(), QFlag(m_findFlag & ~QWebPage::HighlightAllOccurrences));
1130 m_findFlag = m_findFlag ^ mode;
1132 if (found || m_lineEdit->text().isEmpty())
1133 m_lineEdit->setPalette(palette);
1135 palette.setColor(m_lineEdit->backgroundRole(), QColor(255, 0, 0, 127));
1136 m_lineEdit->setPalette(palette);
1140 if (m_findFlag & QWebPage::HighlightAllOccurrences)
1141 page()->findText(m_lineEdit->text(), QFlag(m_findFlag));