ConfigDialog.cpp

Go to the documentation of this file.
00001 /*
00002 **  This file is part of Vidalia, and is subject to the license terms in the
00003 **  LICENSE file, found in the top level directory of this distribution. If you
00004 **  did not receive the LICENSE file with this file, you may obtain it from the
00005 **  Vidalia source package distributed by the Vidalia Project at
00006 **  http://www.vidalia-project.net/. No part of Vidalia, including this file,
00007 **  may be copied, modified, propagated, or distributed except according to the
00008 **  terms described in the LICENSE file.
00009 */
00010 
00011 /* 
00012 ** \file ConfigDialog.cpp
00013 ** \version $Id: ConfigDialog.cpp 3735 2009-04-28 20:28:01Z edmanm $
00014 ** \brief Contains a series of Vidalia and Tor configuration pages
00015 */
00016 
00017 #include "ConfigDialog.h"
00018 #include "GeneralPage.h"
00019 #include "NetworkPage.h"
00020 #include "ServerPage.h"
00021 #include "AdvancedPage.h"
00022 #include "AppearancePage.h"
00023 #include "ServicePage.h"
00024 #include "VMessageBox.h"
00025 #include "ServerSettings.h"
00026 #include "NetworkSettings.h"
00027 #include "Vidalia.h"
00028 
00029 #include "html.h"
00030 
00031 
00032 /* Images for toolbar icons */
00033 #define IMAGE_GENERAL       ":/images/32x32/preferences-system.png"
00034 #define IMAGE_NETWORK       ":/images/32x32/preferences-system-network.png"
00035 #define IMAGE_SERVER        ":/images/32x32/preferences-system-network-sharing.png"
00036 #define IMAGE_APPEARANCE    ":/images/32x32/preferences-desktop-locale.png"
00037 #define IMAGE_ADVANCED      ":/images/32x32/applications-system.png"
00038 #define IMAGE_HELP          ":/images/32x32/system-help.png"
00039 #define IMAGE_SERVICE       ":/images/32x32/services.png"
00040 
00041 
00042 /** Constructor */
00043 ConfigDialog::ConfigDialog(QWidget* parent)
00044 : VidaliaWindow("ConfigDialog", parent)
00045 {
00046   /* Invoke the Qt Designer generated QObject setup routine */
00047   ui.setupUi(this);
00048  
00049   /* Override the QDialogButtonBox button text so we can use our own
00050    * translations. */
00051   QPushButton *button = ui.buttonBox->button(QDialogButtonBox::Ok);
00052   if (button) {
00053     Vidalia::createShortcut(QKeySequence(Qt::Key_Return), 
00054                             this, button, SLOT(click()));
00055   }
00056   button = ui.buttonBox->button(QDialogButtonBox::Cancel);
00057   if (button) {
00058     Vidalia::createShortcut("Esc", this, button, SLOT(click()));
00059     Vidalia::createShortcut("Ctrl+W", this, button, SLOT(click()));
00060   }
00061   
00062   /* Connect the button box signals to the appropriate slots */
00063   connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(saveChanges()));
00064   connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(close()));
00065   connect(ui.buttonBox, SIGNAL(helpRequested()), this, SLOT(help()));
00066   connect(Vidalia::torControl(), SIGNAL(authenticated()),
00067                            this, SLOT(applyChanges()));
00068 
00069   /* Create the config pages and actions */
00070   QActionGroup *grp = new QActionGroup(this);
00071   GeneralPage *generalPage = new GeneralPage(ui.stackPages);
00072   ui.stackPages->add(generalPage,
00073                      createPageAction(QIcon(IMAGE_GENERAL),
00074                                       tr("General"), "General", grp));
00075   connect(generalPage, SIGNAL(checkForUpdates()),
00076           this, SLOT(onCheckForUpdates()));
00077 
00078   ui.stackPages->add(new NetworkPage(ui.stackPages),
00079                      createPageAction(QIcon(IMAGE_NETWORK),
00080                                       tr("Network"), "Network", grp));
00081 
00082   ui.stackPages->add(new ServerPage(ui.stackPages),
00083                      createPageAction(QIcon(IMAGE_SERVER),
00084                                       tr("Sharing"), "Sharing", grp));
00085 
00086   ui.stackPages->add(new ServicePage(ui.stackPages),
00087                      createPageAction(QIcon(IMAGE_SERVICE),
00088                                       tr("Services"), "Services", grp));
00089 
00090   ui.stackPages->add(new AppearancePage(ui.stackPages),
00091                      createPageAction(QIcon(IMAGE_APPEARANCE),
00092                                       tr("Appearance"), "Appearance", grp));
00093 
00094   ui.stackPages->add(new AdvancedPage(ui.stackPages),
00095                      createPageAction(QIcon(IMAGE_ADVANCED),
00096                                       tr("Advanced"), "Advanced", grp));
00097 
00098   foreach (ConfigPage *page, ui.stackPages->pages()) {
00099     connect(page, SIGNAL(helpRequested(QString)),
00100             this, SLOT(help(QString)));
00101   }
00102 
00103   /* Create the toolbar */
00104   ui.toolBar->addActions(grp->actions());
00105   ui.toolBar->addSeparator();
00106   connect(grp, SIGNAL(triggered(QAction *)), 
00107           ui.stackPages, SLOT(showPage(QAction *)));
00108   
00109   /* Create and bind the Help button */
00110   QAction *helpAct = new QAction(QIcon(IMAGE_HELP), tr("Help"), ui.toolBar);
00111   helpAct->setData("Help");
00112   addAction(helpAct, SLOT(help()));
00113 
00114   /* Select the first action */
00115   grp->actions()[0]->setChecked(true);
00116 
00117 #if defined(Q_WS_WIN)
00118   helpAct->setShortcut(QString("F1"));
00119 #else
00120   helpAct->setShortcut(QString("Ctrl+?"));
00121 #endif
00122 }
00123 
00124 /** Creates a new action associated with a config page. */
00125 QAction*
00126 ConfigDialog::createPageAction(const QIcon &img, const QString &text, 
00127                                const QString &data, QActionGroup *group)
00128 {
00129   QAction *action = new QAction(img, text, group);
00130   action->setData(data);
00131   action->setCheckable(true);
00132   return action;
00133 }
00134 
00135 /** Adds the given action to the toolbar and hooks its triggered() signal to
00136  * the specified slot (if given). */
00137 void
00138 ConfigDialog::addAction(QAction *action, const char *slot)
00139 {
00140   ui.toolBar->addAction(action);
00141   connect(action, SIGNAL(triggered()), this, slot);
00142 }
00143 
00144 /** Shows the config dialog with focus set to the given page. */
00145 void
00146 ConfigDialog::showWindow(Page page)
00147 {
00148   /* Load saved settings */
00149   loadSettings();
00150   /* Show the dialog. */
00151   VidaliaWindow::showWindow();
00152   /* Set the focus to the specified page. */
00153   ui.stackPages->setCurrentIndex((int)page);
00154 }
00155 
00156 /** Called when the user changes the UI translation. */
00157 void
00158 ConfigDialog::retranslateUi()
00159 {
00160   ui.retranslateUi(this);
00161   foreach (ConfigPage *page, ui.stackPages->pages()) {
00162     page->retranslateUi();
00163   }
00164   foreach (QAction *action, ui.toolBar->actions()) {
00165     action->setText(tr(qPrintable(action->data().toString()), "ConfigDialog"));
00166   }
00167   ui.buttonBox->setStandardButtons(ui.buttonBox->standardButtons());
00168 }
00169 
00170 /** Loads the saved ConfigDialog settings. */
00171 void
00172 ConfigDialog::loadSettings()
00173 {
00174   /* Call each config page's load() method to load its data */
00175   foreach (ConfigPage *page, ui.stackPages->pages()) {
00176     page->load();
00177   }
00178 }
00179 
00180 /** Saves changes made to settings. If Tor is running and Vidalia is
00181  * connected, we will also attempt to apply the changes to Tor. */
00182 void
00183 ConfigDialog::saveChanges()
00184 {
00185   QString errmsg;
00186   
00187   /* Call each config page's save() method to save its data */
00188   foreach (ConfigPage *page, ui.stackPages->pages()) {
00189     if (!page->save(errmsg)) {
00190       /* Display the offending page */
00191       ui.stackPages->setCurrentPage(page);
00192       
00193       /* Show the user what went wrong */
00194       VMessageBox::warning(this, 
00195         tr("Error Saving Settings"), 
00196         p(tr("Vidalia was unable to save your %1 settings.")
00197              .arg(tr(qPrintable(page->title()), "ConfigDialog"))) + p(errmsg),
00198         VMessageBox::Ok);
00199 
00200       /* Don't process the rest of the pages */
00201       return;
00202     }
00203   }
00204   if (Vidalia::torControl()->isConnected())
00205     applyChanges();
00206   else
00207     close();
00208 }
00209 
00210 /** Called after Vidalia has authenticated to Tor and applies any changes
00211  * made since the last time they were applied. */
00212 void
00213 ConfigDialog::applyChanges()
00214 {
00215   QString errmsg;
00216   bool appliedChanges = false;
00217 
00218   foreach (ConfigPage *page, ui.stackPages->pages()) {
00219     if (!page->changedSinceLastApply())
00220       continue;
00221     if (!page->apply(errmsg)) {
00222       /* Failed to apply the changes to Tor */
00223       int ret = VMessageBox::warning(this,
00224                   tr("Error Applying Settings"),
00225                   p(tr("Vidalia was unable to apply your %1 settings "
00226                        "to Tor.").arg(page->title()))
00227                     + p(errmsg),
00228                   VMessageBox::ShowSettings|VMessageBox::Default,
00229                   VMessageBox::Cancel|VMessageBox::Escape);
00230       if (ret == VMessageBox::ShowSettings) {
00231         /* Show the user the page with the bad settings */
00232         showWindow();
00233         ui.stackPages->setCurrentPage(page);
00234       } else {
00235         /* The user clicked 'Cancel', so revert the failed settings */
00236         page->revert();
00237         close();
00238       }
00239       return;
00240     }
00241     appliedChanges = true;
00242   }
00243   if (appliedChanges)
00244     saveConf();      
00245   close();
00246 }
00247 
00248 /** Sends Tor a SAVECONF to write its configuration to disk. If the SAVECONF
00249  * is successful, then all settings are considered to be applied. */
00250 void
00251 ConfigDialog::saveConf()
00252 {
00253   TorControl *tc = Vidalia::torControl();
00254   if (tc->saveConf()) {
00255     ServerSettings(tc).setChanged(false);
00256     NetworkSettings(tc).setChanged(false);
00257     TorSettings(tc).setChanged(false);
00258   }
00259 }
00260 
00261 /** Shows help information for whichever settings page the user is currently
00262  * viewing. */
00263 void
00264 ConfigDialog::help()
00265 {
00266   Page currentPage = static_cast<Page>(ui.stackPages->currentIndex());
00267   
00268   switch (currentPage) {
00269     case Network:
00270       help("config.network"); break;
00271     case Server:
00272       help("server"); break;
00273     case Appearance:
00274       help("config.appearance"); break;
00275     case Advanced:
00276       help("config.advanced"); break;
00277     case Service:
00278       help("config.services"); break;
00279     default:
00280       help("config.general"); break;
00281   }
00282 }
00283 
00284 /** Stub method that relays the checkForUpdates() signal from the General
00285  * settings page to the owner of the config dialog (MainWindow). */
00286 void
00287 ConfigDialog::onCheckForUpdates()
00288 {
00289   emit checkForUpdates();
00290 }
00291 
00292 
00293 /** Called when a ConfigPage in the dialog requests help on a specific
00294  * <b>topic</b>. */
00295 void
00296 ConfigDialog::help(const QString &topic)
00297 {
00298   emit helpRequested(topic);
00299 }
00300 

Generated on Mon Aug 30 19:09:59 2010 for Vidalia by  doxygen 1.5.9