////////////////////////////////////////////////////////////////////////// // // pgAdmin 4 - PostgreSQL Tools // // Copyright (C) 2013 - 2016, The pgAdmin Development Team // This software is released under the PostgreSQL Licence // // BrowserWindow.cpp - Implementation of the main window class // ////////////////////////////////////////////////////////////////////////// #include "pgAdmin4.h" #if QT_VERSION >= 0x050000 #include #include #else #include #include #include #include #include #include #include #endif #include #include // App headers #include "BrowserWindow.h" #include "ConfigWindow.h" // Constructor BrowserWindow::BrowserWindow(QString url) { m_tabGridLayout = NULL; m_mainGridLayout = NULL;; m_tabWidget = NULL; m_pgAdminMainTab = NULL; m_addNewTab = NULL; m_addNewGridLayout = NULL; m_addNewWebView = NULL; m_horizontalLayout = NULL; m_widget = NULL; m_toolBtnBack = NULL; m_toolBtnForward = NULL; m_downloadStarted = 0; m_downloadCancelled = 0; m_file = NULL; m_downloadFilename = ""; m_defaultFilename = ""; m_progressDialog = NULL; m_last_open_folder_path = ""; m_dir = ""; m_reply = NULL; m_appServerUrl = url; // Setup the shortcuts createActions(); m_tabWidget = new TabWindow(this); m_mainGridLayout = new QGridLayout(m_tabWidget); m_mainGridLayout->setContentsMargins(0, 0, 0, 0); m_pgAdminMainTab = new QWidget(m_tabWidget); m_tabGridLayout = new QGridLayout(m_pgAdminMainTab); m_tabGridLayout->setContentsMargins(0, 0, 0, 0); m_mainWebView = new WebViewWindow(m_pgAdminMainTab); #ifdef PGADMIN4_DEBUG // If pgAdmin4 is run in debug mode, then we should enable the // "Inspect" option, when the user right clicks on QWebView widget. // This option is useful to debug the pgAdmin4 desktop application and open the developer tools. QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); #endif #ifdef __APPLE__ m_mainWebView->setStyle(QStyleFactory::create("Fusion")); #endif m_tabGridLayout->addWidget(m_mainWebView, 0, 0, 1, 1); m_tabWidget->addTab(m_pgAdminMainTab, QString()); m_tabWidget->setCurrentIndex(0); m_tabWidget->setTabText(0, PGA_APP_NAME); m_tabWidget->setTabToolTipText(0, PGA_APP_NAME) ; setCentralWidget(m_tabWidget); connect(m_mainWebView, SIGNAL(loadFinished(bool)), SLOT(finishLoading(bool))); // Register the slot when click on the URL link form main menu bar connect(m_mainWebView, SIGNAL(linkClicked(const QUrl &)),SLOT(urlLinkClicked(const QUrl &))); // Register the slot on tab index change connect(m_tabWidget,SIGNAL(currentChanged(int )),this,SLOT(tabIndexChanged(int ))); // Listen for download file request from the web page m_mainWebView->page()->setForwardUnsupportedContent(true); connect(m_mainWebView->page(), SIGNAL(downloadRequested(const QNetworkRequest &)), this, SLOT(download(const QNetworkRequest &))); connect(m_mainWebView->page(), SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*))); m_mainWebView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); // Restore the geometry QSettings settings; restoreGeometry(settings.value("Browser/Geometry").toByteArray()); restoreState(settings.value("Browser/WindowState").toByteArray()); // Set the initial zoom qreal zoom = settings.value("Browser/Zoom", m_mainWebView->zoomFactor()).toReal(); m_mainWebView->setZoomFactor(zoom); // The last save location m_last_open_folder_path = settings.value("Browser/LastSaveLocation", QDir::homePath()).toString(); // Display the app m_initialLoad = true; m_loadAttempt = 1; m_mainWebView->setUrl(m_appServerUrl); } // Save the window geometry on close void BrowserWindow::closeEvent(QCloseEvent *event) { QSettings settings; settings.setValue("Browser/Geometry", saveGeometry()); settings.setValue("Browser/WindowState", saveState()); QMainWindow::closeEvent(event); } // Create the actions for the window void BrowserWindow::createActions() { // Open an arbitrary URL openUrlShortcut = new QShortcut(QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_U), this); openUrlShortcut->setContext(Qt::ApplicationShortcut); connect(openUrlShortcut, SIGNAL(activated()), this, SLOT(openUrl())); // Set the Python Path preferencesShortcut = new QShortcut(QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_P), this); preferencesShortcut->setContext(Qt::ApplicationShortcut); connect(preferencesShortcut, SIGNAL(activated()), this, SLOT(preferences())); // Exit the app exitShortcut = new QShortcut(QKeySequence::Quit, this); exitShortcut->setContext(Qt::ApplicationShortcut); connect(exitShortcut, SIGNAL(activated()), this, SLOT(close())); // About box aboutShortcut = new QShortcut(QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_A), this); aboutShortcut->setContext(Qt::ApplicationShortcut); connect(aboutShortcut, SIGNAL(activated()), this, SLOT(about())); // Zoom in zoomInShortcut = new QShortcut(QKeySequence(QKeySequence::ZoomIn), this); zoomInShortcut->setContext(Qt::ApplicationShortcut); connect(zoomInShortcut, SIGNAL(activated()), this, SLOT(zoomIn())); // Zoom out zoomOutShortcut = new QShortcut(QKeySequence(QKeySequence::ZoomOut), this); zoomOutShortcut->setContext(Qt::ApplicationShortcut); connect(zoomOutShortcut, SIGNAL(activated()), this, SLOT(zoomOut())); } // Process loading finished signals from the web view. void BrowserWindow::finishLoading(bool ok) { if (m_initialLoad && !ok) { // The load attempt failed. Try again up to 4 times with an // incremental backoff. if (m_loadAttempt < 5) { if (m_loadAttempt > 1) { qDebug() << "Initial connection failed. Retrying in" << m_loadAttempt << "seconds."; m_mainWebView->setHtml(QString(tr("

Failed to connect to the pgAdmin application server. Retrying in %1 seconds, ") + tr("or click here to try again now.

")).arg(m_loadAttempt).arg(m_appServerUrl)); } else { m_mainWebView->setHtml(QString(tr("

Connecting to the application server...

"))); } pause(m_loadAttempt); m_mainWebView->setUrl(m_appServerUrl); m_loadAttempt++; return; } else { qDebug() << "Initial connection failed after multiple attempts. Aborting."; m_mainWebView->setHtml(QString(tr("

Failed to connect to the pgAdmin application server. ") + tr("Click here to try again.

")).arg(m_appServerUrl)); } } m_initialLoad = false; } // Check if Tab is already open with given URL name int BrowserWindow::findURLTab(const QUrl &name) { int tabCount = 0; WebViewWindow *webviewPtr = NULL; for (tabCount = 1; tabCount < m_tabWidget->count(); tabCount++) { QWidget *tab = m_tabWidget->widget(tabCount); if (tab != NULL) { QList widgetList = tab->findChildren(); foreach( QWidget* widgetPtr, widgetList ) { if (widgetPtr != NULL) { webviewPtr = dynamic_cast(widgetPtr); if (webviewPtr != NULL && !QString::compare(webviewPtr->getFirstLoadURL(),name.host(), Qt::CaseInsensitive)) { m_tabWidget->setCurrentIndex(tabCount); return 1; } } } } } return 0; } // Below slot will be called when user right click on download link and select "Save Link..." option from context menu void BrowserWindow::download(const QNetworkRequest &request) { // Check that request contains data for download at client side QUrl name; if (m_downloadStarted) { // Inform user that a download is already started QMessageBox::information(this, tr("Download warning"), tr("File download already in progress: %1").arg(m_defaultFilename)); return; } m_defaultFilename = QFileInfo(request.url().toString()).fileName(); // Open the dialog to save file QFileDialog save_dialog(this); save_dialog.setAcceptMode(QFileDialog::AcceptSave); save_dialog.setWindowTitle(tr("Save file")); save_dialog.setDirectory(m_last_open_folder_path); save_dialog.selectFile(m_defaultFilename); // Register the slot for directory travesing when file dialog is opened and save the last open directory QObject::connect(&save_dialog, SIGNAL(directoryEntered(const QString &)), this, SLOT(current_dir_path(const QString &))); m_dir = m_last_open_folder_path; QString fileName = ""; QString f_name = ""; if (save_dialog.exec() == QDialog::Accepted) { fileName = save_dialog.selectedFiles().first(); f_name = fileName.replace(m_dir, ""); // Remove the first character(/) from fiename f_name.remove(0,1); m_defaultFilename = f_name; } else return; fileName = m_dir + fileName; // Clear the last open directory path m_dir.clear(); #ifdef __APPLE__ // Check that user has given valid file name or not - forward slash is not allowed in file name // In Mac OSX, forward slash is converted to colon(:) by Qt so we need to check for colon. if (f_name.indexOf(":") != -1) { QMessageBox::information(this, tr("File name error"), tr("Invalid file name")); return; } #else // Check that user has given valid file name or not - forward slash is not allowed in file name if (f_name.indexOf("/") != -1) { QMessageBox::information(this, tr("File name error"), tr("Invalid file name")); return; } #endif if (fileName.isEmpty()) return; else { m_downloadFilename = fileName; QNetworkRequest newRequest = request; newRequest.setAttribute(QNetworkRequest::User, fileName); QObject *obj_web_page = QObject::sender(); if (obj_web_page != NULL) { QWebPage *sender_web_page = dynamic_cast(obj_web_page); if (sender_web_page != NULL) { QNetworkAccessManager *networkManager = sender_web_page->networkAccessManager(); QNetworkReply *reply = networkManager->get(newRequest); if (reply != NULL) { m_downloadStarted = 1; m_downloadCancelled = 0; // Connect the signals for downloadProgress and downloadFinished connect( reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadFileProgress(qint64, qint64)) ); connect( reply, SIGNAL(finished()), this, SLOT(downloadFinished())); } } } } } // Below slot will be called when file download is in progress void BrowserWindow::downloadFileProgress(qint64 readData, qint64 totalData) { QNetworkReply *reply = ((QNetworkReply*)sender()); QNetworkRequest request = reply->request(); QVariant v = request.attribute(QNetworkRequest::User); // When download is canceled by user then no need to write data to file if (m_downloadCancelled) return; if(reply != NULL && reply->error() != QNetworkReply::NoError) { qDebug() << "Network error occurred whilst downloading: " << m_defaultFilename; return; } // Download is started so open the file if (!m_file) { m_file = new QFile(m_downloadFilename); if (!m_file->open(QIODevice::WriteOnly)) { qDebug() << "Error opening file: " << m_downloadFilename; m_downloadFilename.clear(); m_defaultFilename.clear(); m_downloadStarted = 0; return; } // Create progress bar dialog m_progressDialog = new QProgressDialog (tr("Downloading file: %1 ").arg(m_defaultFilename), "Cancel", readData, totalData, this); m_progressDialog->setWindowModality(Qt::WindowModal); m_progressDialog->setWindowTitle(tr("Download progress")); m_progressDialog->setMinimumWidth(450); m_progressDialog->setMinimumHeight(80); m_progressDialog->setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint); // Register slot for file download cancel request QObject::connect(m_progressDialog, SIGNAL(canceled()), this, SLOT(progressCanceled())); m_reply = reply; // Show downloading progress bar m_progressDialog->show(); } if (m_file) { // Write data to file m_file->write(reply->read(readData)); m_progressDialog->setValue(readData); // As read data and totalData difference is zero means downloading is finished. if ((totalData - readData) == 0 || (readData != 0 && totalData == -1)) { // As downloading is finished so remove progress bar dialog if (m_progressDialog) { m_progressDialog->deleteLater(); m_progressDialog = NULL; } m_downloadStarted = 0; m_downloadFilename.clear(); m_defaultFilename.clear(); m_downloadCancelled = 0; if (m_file) { m_file->close(); delete m_file; m_file = NULL; } if (m_reply) m_reply = NULL; } } } // Below slot will be called when user cancel the downloading file which is in progress. void BrowserWindow::progressCanceled() { m_downloadCancelled = 1; if (m_progressDialog) { m_progressDialog->deleteLater(); m_progressDialog = NULL; } if (m_file) { m_file->close(); // Remove the file from file system as downloading is canceled by user m_file->remove(); delete m_file; m_file = NULL; } if (m_reply) { m_reply->abort(); m_reply = NULL; } m_downloadFilename.clear(); m_defaultFilename.clear(); m_downloadStarted = 0; } // Below slot will called when file download is finished void BrowserWindow::downloadFinished() { if (m_progressDialog) { m_progressDialog->deleteLater(); m_progressDialog = NULL; } m_downloadFilename.clear(); m_defaultFilename.clear(); m_downloadStarted = 0; m_downloadCancelled = 0; if (m_file) { m_file->close(); delete m_file; m_file = NULL; } if (m_reply) m_reply = NULL; } // Below slot will be called when user directly click on any download link void BrowserWindow::unsupportedContent(QNetworkReply * reply) { #if QT_VERSION >= 0x050000 // Extract filename and query from encoded URL QUrlQuery query_data(reply->url()); QString file_name = query_data.queryItemValue("filename"); QString query = query_data.queryItemValue("query"); #else QUrl url(reply->url()); QString file_name = url.queryItemValue("filename"); QString query = url.queryItemValue("query"); #endif if (m_downloadStarted) { // Inform user that download is already started QMessageBox::information(this, tr("Download warning"), tr("File download already in progress: %1").arg(m_defaultFilename)); return; } // If encoded URL contains 'filename' attribute then use that filename in file dialog. if (file_name.isEmpty() && query.isEmpty()) m_defaultFilename = QFileInfo(reply->url().toString()).fileName(); else m_defaultFilename = file_name; QFileDialog save_dialog(this); save_dialog.setAcceptMode(QFileDialog::AcceptSave); save_dialog.setWindowTitle(tr("Save file")); save_dialog.setDirectory(m_last_open_folder_path); save_dialog.selectFile(m_defaultFilename); QObject::connect(&save_dialog, SIGNAL(directoryEntered(const QString &)), this, SLOT(current_dir_path(const QString &))); m_dir = m_last_open_folder_path; QString fileName = ""; QString f_name = ""; if (save_dialog.exec() == QDialog::Accepted) { fileName = save_dialog.selectedFiles().first(); f_name = fileName.replace(m_dir, ""); // Remove the first character(/) from fiename f_name.remove(0,1); m_defaultFilename = f_name; } else return; fileName = m_dir + fileName; // Clear last open folder path m_dir.clear(); #ifdef __APPLE__ // Check that user has given valid file name or not - forward slash is not allowed in file name // In Mac OSX, forward slash is converted to colon(:) by Qt so we need to check for colon. if (f_name.indexOf(":") != -1) { QMessageBox::information(this, tr("File name error"), tr("Invalid file name")); return; } #else // Check that user has given valid file name or not - forward slash is not allowed in file name if (f_name.indexOf("/") != -1) { QMessageBox::information(this, tr("File name error"), tr("Invalid file name")); return; } #endif if (fileName.isEmpty()) return; else { m_downloadFilename = fileName; if (reply != NULL) { m_downloadStarted = 1; m_downloadCancelled = 0; connect( reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadFileProgress(qint64, qint64))); connect( reply, SIGNAL(finished()), this, SLOT(downloadFinished())); } } } // Slot: When the tab index change, hide/show the toolbutton displayed on tab void BrowserWindow::tabIndexChanged(int index) { int tabCount = 1; for (tabCount = 1; tabCount < m_tabWidget->count(); tabCount++) { if (tabCount != index) m_tabWidget->showHideToolButton(tabCount, 0); else m_tabWidget->showHideToolButton(tabCount, 1); } } // Close the tab and remove the memory of the given index tab void BrowserWindow::closetabs() { int loopCount = 0; int index = 0; QPushButton *btn = NULL; int totalTabs = m_tabWidget->count(); // If QTabWidget contains only one tab then hide the TabBar window if ((totalTabs - 1) < 2) m_tabWidget->tabBar()->setVisible(false); else m_tabWidget->tabBar()->setVisible(true); QObject *senderPtr = QObject::sender(); if (senderPtr != NULL) { btn = dynamic_cast(senderPtr); index = m_tabWidget->getButtonIndex(btn); } if (index != 0) { QWidget *tab = m_tabWidget->widget(index); WebViewWindow *webviewPtr = NULL; loopCount = 0; // free the allocated memory when the tab is closed if (tab != NULL) delete tab; // Adjust the tab index value if the tab is closed in between for (loopCount = 1; loopCount < totalTabs; loopCount++) { if (index > loopCount) continue; QWidget *tab = m_tabWidget->widget(loopCount); if (tab != NULL) { QList widgetList = tab->findChildren(); foreach( QWidget* widgetPtr, widgetList ) { if (widgetPtr != NULL) { webviewPtr = dynamic_cast(widgetPtr); if (webviewPtr != NULL) webviewPtr->setTabIndex((webviewPtr->getTabIndex() - 1)); } } } } } } // Slot: go back to page and enable/disable toolbutton void BrowserWindow::goBackPage() { WebViewWindow *webviewPtr = NULL; QWidget *tab = m_tabWidget->widget(m_tabWidget->currentIndex()); if (tab != NULL) { QList widgetList = tab->findChildren(); foreach( QWidget* widgetPtr, widgetList ) { if (widgetPtr != NULL) { webviewPtr = dynamic_cast(widgetPtr); if (webviewPtr != NULL) { webviewPtr->back(); m_tabWidget->enableDisableToolButton(m_tabWidget->currentIndex()); } } } } } // Slot: go forward to page and enable/disable toolbutton void BrowserWindow::goForwardPage() { WebViewWindow *webviewPtr = NULL; QWidget *tab = m_tabWidget->widget(m_tabWidget->currentIndex()); if (tab != NULL) { QList widgetList = tab->findChildren(); foreach( QWidget* widgetPtr, widgetList ) { if (widgetPtr != NULL) { webviewPtr = dynamic_cast(widgetPtr); if (webviewPtr != NULL) { webviewPtr->forward(); m_tabWidget->enableDisableToolButton(m_tabWidget->currentIndex()); } } } } } // Slot: set the title of tab when the new tab created or existing tab contents changed void BrowserWindow::tabTitleChanged(const QString &str) { if (!str.isEmpty()) { QObject *senderPtr = QObject::sender(); WebViewWindow *webViewPtr = NULL; if (senderPtr != NULL) { webViewPtr = dynamic_cast(senderPtr); if (webViewPtr != NULL) { m_tabWidget->setTabText(webViewPtr->getTabIndex(), str); m_tabWidget->setTabToolTipText(webViewPtr->getTabIndex(), str); m_tabWidget->enableDisableToolButton(webViewPtr->getTabIndex()); } } else { m_tabWidget->setTabText(m_tabWidget->currentIndex(), str); m_tabWidget->setTabToolTipText(m_tabWidget->currentIndex(), str); } } } void BrowserWindow::current_dir_path(const QString &dir) { m_dir = dir; m_last_open_folder_path = dir; QSettings settings; settings.setValue("Browser/LastSaveLocation", m_last_open_folder_path); } // Slot: Link is open from pgAdmin mainwindow void BrowserWindow::urlLinkClicked(const QUrl &name) { // Check that request contains the data download at client side QNetworkRequest request; // First check is there any tab opened with same URL then open it again. int tabFound = findURLTab(name); if (!tabFound) { m_addNewTab = new QWidget(m_tabWidget); m_addNewGridLayout = new QGridLayout(m_addNewTab); m_addNewGridLayout->setContentsMargins(0, 0, 0, 0); m_addNewWebView = new WebViewWindow(m_addNewTab); m_addNewWebView->setZoomFactor(m_mainWebView->zoomFactor()); // Listen for the download request from the web page m_addNewWebView->page()->setForwardUnsupportedContent(true); connect(m_addNewWebView->page(), SIGNAL(downloadRequested(const QNetworkRequest &)), this, SLOT(download(const QNetworkRequest &))); connect(m_addNewWebView->page(), SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*))); m_widget = new QWidget(m_addNewTab); m_toolBtnBack = new QToolButton(m_widget); m_toolBtnBack->setFixedHeight(PGA_BTN_SIZE); m_toolBtnBack->setFixedWidth(PGA_BTN_SIZE); m_toolBtnBack->setIcon(QIcon(":/back.png")); m_toolBtnBack->setToolTip(tr("Go back")); m_toolBtnBack->setDisabled(true); m_toolBtnForward = new QToolButton(m_widget); m_toolBtnForward->setFixedHeight(PGA_BTN_SIZE); m_toolBtnForward->setFixedWidth(PGA_BTN_SIZE); m_toolBtnForward->setIcon(QIcon(":/forward.png")); m_toolBtnForward->setToolTip(tr("Go forward")); m_toolBtnForward->setDisabled(true); QPushButton *m_btnClose = new QPushButton(m_widget); m_btnClose->setFixedHeight(PGA_BTN_SIZE); m_btnClose->setFixedWidth(PGA_BTN_SIZE); m_btnClose->setIcon(QIcon(":/close.png")); m_btnClose->setToolTip(tr("Close tab")); m_horizontalLayout = new QHBoxLayout(m_widget); m_horizontalLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); m_horizontalLayout->setSpacing(1); m_horizontalLayout->addWidget(m_toolBtnBack); m_horizontalLayout->addWidget(m_toolBtnForward); // Register the slot on titleChange so set the tab text accordingly connect(m_addNewWebView, SIGNAL(titleChanged(const QString &)), SLOT(tabTitleChanged(const QString &))); // Register the slot on toolbutton to show the previous history of web connect(m_toolBtnBack, SIGNAL(clicked()), this, SLOT(goBackPage())); // Register the slot on toolbutton to show the next history of web connect(m_toolBtnForward, SIGNAL(clicked()), this, SLOT(goForwardPage())); // Register the slot on close button , added manually connect(m_btnClose, SIGNAL(clicked()), SLOT(closetabs())); m_addNewGridLayout->addWidget(m_addNewWebView, 0, 0, 1, 1); m_tabWidget->addTab(m_addNewTab, QString()); m_tabWidget->tabBar()->setVisible(true); m_tabWidget->setCurrentIndex((m_tabWidget->count() - 1)); // Set the back and forward button on tab m_tabWidget->tabBar()->setTabButton((m_tabWidget->count() - 1), QTabBar::LeftSide, m_widget); m_tabWidget->tabBar()->setTabButton((m_tabWidget->count() - 1), QTabBar::RightSide, m_btnClose); m_addNewWebView->setFirstLoadURL(name.host()); m_addNewWebView->setTabIndex((m_tabWidget->count() - 1)); m_addNewWebView->setUrl(name); } } // Pause for n seconds, without freezing the UI. void BrowserWindow::pause(int seconds) { QTime dieTime = QTime::currentTime().addSecs(seconds); while (QTime::currentTime() < dieTime) QCoreApplication::processEvents(QEventLoop::AllEvents, 100); } // Display the about box void BrowserWindow::about() { QMessageBox::about(this, tr("About %1").arg(PGA_APP_NAME), tr("%1 - PostgreSQL Tools").arg(PGA_APP_NAME)); } // Zoom in void BrowserWindow::zoomIn() { int tabCount = 0; WebViewWindow *webviewPtr = NULL; // Loop through all the tabs for (tabCount = 0; tabCount < m_tabWidget->count(); tabCount++) { QWidget *tab = m_tabWidget->widget(tabCount); if (tab != NULL) { // Find and loop through any child controls QList widgetList = tab->findChildren(); foreach( QWidget* widgetPtr, widgetList ) { if (widgetPtr != NULL) { // If it's a web view control, set the zoom level based on the main view webviewPtr = dynamic_cast(widgetPtr); if (webviewPtr != NULL) { webviewPtr->setZoomFactor(m_mainWebView->zoomFactor() + 0.1); } } } } } // Save the zoom factor for next time QSettings settings; settings.setValue("Browser/Zoom", m_mainWebView->zoomFactor()); } // Zoom out void BrowserWindow::zoomOut() { int tabCount = 0; WebViewWindow *webviewPtr = NULL; // Loop through all the tabs for (tabCount = 0; tabCount < m_tabWidget->count(); tabCount++) { QWidget *tab = m_tabWidget->widget(tabCount); if (tab != NULL) { // Find and loop through any child controls QList widgetList = tab->findChildren(); foreach( QWidget* widgetPtr, widgetList ) { if (widgetPtr != NULL) { // If it's a web view control, set the zoom level based on the main view webviewPtr = dynamic_cast(widgetPtr); if (webviewPtr != NULL) { webviewPtr->setZoomFactor(m_mainWebView->zoomFactor() - 0.1); } } } } } // Save the zoom factor for next time QSettings settings; settings.setValue("Browser/Zoom", m_mainWebView->zoomFactor()); } // Open an arbitrary URL void BrowserWindow::openUrl() { bool ok; QInputDialog *dlg = new QInputDialog(); dlg->setInputMode(QInputDialog::TextInput); dlg->setWindowTitle(QWidget::tr("Open URL")); dlg->setLabelText(QWidget::tr("Enter a URL")); dlg->setTextValue("http://"); dlg->resize(600,100); ok = dlg->exec(); QString url = dlg->textValue(); if (ok && !url.isEmpty()) urlLinkClicked(QUrl(url)); } // Edit the app configuration void BrowserWindow::preferences() { QSettings settings; bool ok; ConfigWindow *dlg = new ConfigWindow(); dlg->setWindowTitle(QWidget::tr("Configuration")); dlg->setPythonPath(settings.value("PythonPath").toString()); dlg->setApplicationPath(settings.value("ApplicationPath").toString()); dlg->setModal(true); ok = dlg->exec(); QString pythonpath = dlg->getPythonPath(); QString applicationpath = dlg->getApplicationPath(); if (ok) { settings.setValue("PythonPath", pythonpath); settings.setValue("ApplicationPath", applicationpath); } }