blob: d9c440915a462aead1da1f0655148e18407d06ab [file] [log] [blame]
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2016, Regents of the University of California.
Jared Lindblom06405c42013-01-17 20:48:39 -08004 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08005 * This file is part of ChronoShare, a decentralized file sharing application over NDN.
Jared Lindblom06405c42013-01-17 20:48:39 -08006 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08007 * ChronoShare is free software: you can redistribute it and/or modify it under the terms
8 * of the GNU General Public License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
Jared Lindblom06405c42013-01-17 20:48:39 -080010 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -080011 * ChronoShare is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
Jared Lindblom06405c42013-01-17 20:48:39 -080014 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -080015 * You should have received copies of the GNU General Public License along with
16 * ChronoShare, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * See AUTHORS.md for complete list of ChronoShare authors and contributors.
Jared Lindblom06405c42013-01-17 20:48:39 -080019 */
20
Alexander Afanasyevf4cde4e2016-12-25 13:42:57 -080021#include "chronosharegui.hpp"
Alexander Afanasyeve83c0562016-12-24 10:20:41 -080022#include "core/chronoshare-config.hpp"
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -080023
Alexander Afanasyevf4cde4e2016-12-25 13:42:57 -080024#include "logging.hpp"
25#include "ccnx-wrapper.hpp"
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080026#include <QValidator>
Zhenkai Zhuce04cb42013-02-25 15:29:31 -080027#include <QDir>
Zhenkai Zhu25e13582013-02-27 15:33:01 -080028#include <QFileInfo>
Zhenkai Zhuce04cb42013-02-25 15:29:31 -080029#include <QDesktopServices>
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -080030
31#include <boost/make_shared.hpp>
32
33using namespace boost;
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070034using namespace Ndnx;
Jared Lindblom06405c42013-01-17 20:48:39 -080035
Zhenkai Zhud9429222013-02-25 22:34:09 -080036static const string HTTP_SERVER_ADDRESS = "localhost";
37static const string HTTP_SERVER_PORT = "9001";
Zhenkai Zhu6b53f932013-03-02 20:46:02 -080038#ifdef _DEBUG
Zhenkai Zhu5c2475b2013-02-26 22:57:31 -080039static const string DOC_ROOT = "gui/html";
Zhenkai Zhu6b53f932013-03-02 20:46:02 -080040#else
41static const string DOC_ROOT = ":/html";
42#endif
Alexander Afanasyevcf771142013-03-19 11:15:27 -070043static const QString ICON_BIG_FILE(":/images/chronoshare-big.png");
44static const QString ICON_TRAY_FILE(":/images/" TRAY_ICON);
Zhenkai Zhud9429222013-02-25 22:34:09 -080045
Alexander Afanasyev83a53002013-01-24 11:12:01 -080046INIT_LOGGER ("Gui");
47
48ChronoShareGui::ChronoShareGui(QWidget *parent)
Jared Lindblomc8ffd592013-01-25 00:00:30 -080049 : QDialog(parent)
Zhenkai Zhud5756312013-01-31 13:49:45 -080050 , m_watcher(0)
51 , m_dispatcher(0)
Zhenkai Zhud9429222013-02-25 22:34:09 -080052 , m_httpServer(0)
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -080053#ifdef ADHOC_SUPPORTED
54 , m_executor (1)
55#endif
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -080056#ifdef SPARKLE_SUPPORTED
Zhenkai Zhu8e3e9072013-02-28 15:40:51 -080057 , m_autoUpdate(new SparkleAutoUpdate(tr("http://irl.cs.ucla.edu/~zhenkai/chronoshare_dist/chronoshare.xml")))
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -080058#endif
Jared Lindblom06405c42013-01-17 20:48:39 -080059{
Jared Lindblomf4b900e2013-02-07 18:08:47 -080060 setWindowTitle("Settings");
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -080061 setMinimumWidth (600);
Jared Lindblomc8ffd592013-01-25 00:00:30 -080062
Jared Lindblomd8b76ad2013-02-07 20:37:37 -080063 labelUsername = new QLabel("Username (hint: /<username>)");
Jared Lindblomc8ffd592013-01-25 00:00:30 -080064 labelSharedFolder = new QLabel("Shared Folder Name");
65 labelSharedFolderPath = new QLabel("Shared Folder Path");
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080066
Zhenkai Zhud5756312013-01-31 13:49:45 -080067 QRegExp regex("(/[^/]+)+$");
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080068 QValidator *prefixValidator = new QRegExpValidator(regex, this);
69
Jared Lindblomc8ffd592013-01-25 00:00:30 -080070 editUsername = new QLineEdit();
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080071 editUsername->setValidator(prefixValidator);
72
73 QRegExp noPureWhiteSpace("^\\S+.*$");
74 QValidator *wsValidator = new QRegExpValidator(noPureWhiteSpace, this);
Jared Lindblomc8ffd592013-01-25 00:00:30 -080075 editSharedFolder = new QLineEdit();
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080076 editSharedFolder->setValidator(wsValidator);
77
Jared Lindblomc8ffd592013-01-25 00:00:30 -080078 editSharedFolderPath = new QLineEdit();
79 editSharedFolderPath->setReadOnly(true);
80 QPalette pal = editSharedFolderPath->palette();
81 pal.setColor(QPalette::Active, QPalette::Base, pal.color(QPalette::Disabled, QPalette::Base));
82 editSharedFolderPath->setPalette(pal);
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -080083 button = new QPushButton("Save and apply settings");
Zhenkai Zhu630d0f12013-02-28 17:21:54 -080084
85 QString versionString = QString("Version: ChronoShare v%1").arg(CHRONOSHARE_VERSION);
86 label = new QLabel(versionString, this);
Jared Lindblomc8ffd592013-01-25 00:00:30 -080087
88 connect(button, SIGNAL(clicked()), this, SLOT(changeSettings()));
89
90 mainLayout = new QVBoxLayout; //vertically
91 mainLayout->addWidget(labelUsername);
92 mainLayout->addWidget(editUsername);
93 mainLayout->addWidget(labelSharedFolder);
94 mainLayout->addWidget(editSharedFolder);
95 mainLayout->addWidget(labelSharedFolderPath);
96 mainLayout->addWidget(editSharedFolderPath);
97 mainLayout->addWidget(button);
98 mainLayout->addWidget(label);
99 setLayout(mainLayout);
100
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800101 // create actions that result from clicking a menu option
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800102 createActionsAndMenu();
Jared Lindblomb4032e22013-01-17 23:50:51 -0800103
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800104 // create tray icon
105 createTrayIcon();
Jared Lindblomb4032e22013-01-17 23:50:51 -0800106
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800107 // set icon image
108 setIcon();
Jared Lindblom06405c42013-01-17 20:48:39 -0800109
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800110 // show tray icon
111 m_trayIcon->show();
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800112
Zhenkai Zhud5756312013-01-31 13:49:45 -0800113 // load settings
114 if(!loadSettings())
115 {
116 // prompt user to choose folder
117 openMessageBox("First Time Setup", "Please enter a username, shared folder name and choose the shared folder path on your local filesystem.");
118 viewSettings();
119 openFileDialog();
120 viewSettings();
121 }
122 else
123 {
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800124 if (m_username.isNull () || m_username == "" ||
125 m_sharedFolderName.isNull () || m_sharedFolderName == "")
126 {
127 openMessageBox("First Time Setup", "To activate ChronoShare, please configure your username and shared folder name.");
128 viewSettings();
129 }
130 else
131 {
132 startBackend();
133 }
Zhenkai Zhud5756312013-01-31 13:49:45 -0800134 }
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800135
136#ifdef ADHOC_SUPPORTED
137 m_executor.start ();
138#endif
Zhenkai Zhud5756312013-01-31 13:49:45 -0800139}
140
141void
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800142ChronoShareGui::startBackend (bool restart/*=false*/)
Zhenkai Zhud5756312013-01-31 13:49:45 -0800143{
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800144 if (m_username.isNull () || m_username=="" ||
145 m_sharedFolderName.isNull () || m_sharedFolderName=="" ||
146 m_dirPath.isNull () || m_dirPath=="")
147 {
148 _LOG_DEBUG ("Don't start backend, because settings are in progress or incomplete");
149 return;
150 }
151
Zhenkai Zhud5756312013-01-31 13:49:45 -0800152 if (m_watcher != 0 && m_dispatcher != 0)
153 {
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800154 if (!restart)
155 {
156 return;
157 }
158
159 _LOG_DEBUG ("Restarting Dispatcher and FileWatcher for the new location or new username");
160 delete m_watcher; // stop filewatching ASAP
161 delete m_dispatcher; // stop dispatcher ASAP, but after watcher (to prevent triggering callbacks on deleted object)
Zhenkai Zhud5756312013-01-31 13:49:45 -0800162 }
163
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800164 filesystem::path realPathToFolder (m_dirPath.toStdString ());
165 realPathToFolder /= m_sharedFolderName.toStdString ();
166
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -0800167 m_dispatcher = new Dispatcher (m_username.toStdString (), m_sharedFolderName.toStdString (),
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700168 realPathToFolder, make_shared<NdnxWrapper> ());
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800169
170 // Alex: this **must** be here, otherwise m_dirPath will be uninitialized
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800171 m_watcher = new FsWatcher (realPathToFolder.string ().c_str (),
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -0800172 bind (&Dispatcher::Did_LocalFile_AddOrModify, m_dispatcher, _1),
Zhenkai Zhud1756272013-02-01 17:02:18 -0800173 bind (&Dispatcher::Did_LocalFile_Delete, m_dispatcher, _1));
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800174
175 if (m_httpServer != 0)
176 {
177 // no need to restart webserver if it already exists
178 return;
179 }
180
Zhenkai Zhud9429222013-02-25 22:34:09 -0800181 QFileInfo indexHtmlInfo(":/html/index.html");
182 if (indexHtmlInfo.exists())
183 {
Zhenkai Zhu8da33652013-03-04 10:52:03 -0800184 try
185 {
186 m_httpServer = new http::server::server(HTTP_SERVER_ADDRESS, HTTP_SERVER_PORT, DOC_ROOT);
187 m_httpServerThread = boost::thread(&http::server::server::run, m_httpServer);
188 }
189 catch (std::exception &e)
190 {
191 _LOG_ERROR ("Start http server failed");
192 m_httpServer = 0; // just to make sure
193 QMessageBox msgBox;
194 msgBox.setText ("WARNING: Cannot start http server!");
195 msgBox.setIcon (QMessageBox::Warning);
196 msgBox.setInformativeText(QString("Starting http server failed. You will not be able to check history from web brower. Exception caused: %1").arg(e.what()));
197 msgBox.setStandardButtons(QMessageBox::Ok);
198 msgBox.exec();
199 }
Zhenkai Zhud9429222013-02-25 22:34:09 -0800200 }
201 else
202 {
203 _LOG_ERROR ("Http server doc root dir does not exist!");
Zhenkai Zhud9429222013-02-25 22:34:09 -0800204 }
Jared Lindblom06405c42013-01-17 20:48:39 -0800205}
206
207ChronoShareGui::~ChronoShareGui()
208{
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800209#ifdef ADHOC_SUPPORTED
210 m_executor.shutdown ();
211#endif
212
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800213 delete m_watcher; // stop filewatching ASAP
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -0800214 delete m_dispatcher; // stop dispatcher ASAP, but after watcher (to prevent triggering callbacks on deleted object)
Zhenkai Zhu8da33652013-03-04 10:52:03 -0800215 if (m_httpServer != 0)
216 {
217 m_httpServer->handle_stop();
218 m_httpServerThread.join();
219 delete m_httpServer;
220 }
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800221
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800222 // cleanup
223 delete m_trayIcon;
224 delete m_trayIconMenu;
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800225#ifdef ADHOC_SUPPORTED
226 delete m_wifiAction;
227#endif
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800228#ifdef SPARKLE_SUPPORTED
229 delete m_autoUpdate;
Zhenkai Zhubb170d42013-02-25 13:48:59 -0800230 delete m_checkForUpdates;
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800231#endif
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800232 delete m_openFolder;
233 delete m_viewSettings;
234 delete m_changeFolder;
235 delete m_quitProgram;
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800236
237 delete labelUsername;
238 delete labelSharedFolder;
239 delete editUsername;
240 delete editSharedFolder;
241 delete button;
242 delete label;
243 delete mainLayout;
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800244}
245
246void ChronoShareGui::openMessageBox(QString title, QString text)
247{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800248 QMessageBox messageBox(this);
249 messageBox.setWindowTitle(title);
250 messageBox.setText(text);
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800251
Alexander Afanasyevcf771142013-03-19 11:15:27 -0700252 messageBox.setIconPixmap(QPixmap(ICON_BIG_FILE));
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800253
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800254 messageBox.exec();
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800255}
256
257void ChronoShareGui::openMessageBox(QString title, QString text, QString infotext)
258{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800259 QMessageBox messageBox(this);
260 messageBox.setWindowTitle(title);
261 messageBox.setText(text);
262 messageBox.setInformativeText(infotext);
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800263
Alexander Afanasyevcf771142013-03-19 11:15:27 -0700264 messageBox.setIconPixmap(QPixmap(ICON_BIG_FILE));
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800265
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800266 messageBox.exec();
Jared Lindblom06405c42013-01-17 20:48:39 -0800267}
268
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800269void ChronoShareGui::createActionsAndMenu()
Jared Lindblom06405c42013-01-17 20:48:39 -0800270{
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800271 _LOG_DEBUG ("Create actions");
272
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800273 // create the "open folder" action
274 m_openFolder = new QAction(tr("&Open Folder"), this);
275 connect(m_openFolder, SIGNAL(triggered()), this, SLOT(openSharedFolder()));
Jared Lindblom06405c42013-01-17 20:48:39 -0800276
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800277 m_openWeb = new QAction(tr("Open in &Browser"), this);
278 connect(m_openWeb, SIGNAL(triggered()), this, SLOT(openInWebBrowser()));
279
280 m_recentFilesMenu = new QMenu(tr("Recently Changed Files"), this);
281 for (int i = 0; i < 5; i++)
282 {
283 m_fileActions[i] = new QAction(this);
284 m_fileActions[i]->setVisible(false);
285 connect(m_fileActions[i], SIGNAL(triggered()), this, SLOT(openFile()));
286 m_recentFilesMenu->addAction(m_fileActions[i]);
287 }
288 connect(m_recentFilesMenu, SIGNAL(aboutToShow()), this, SLOT(updateRecentFilesMenu()));
289
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800290 // create the "view settings" action
291 m_viewSettings = new QAction(tr("&View Settings"), this);
292 connect(m_viewSettings, SIGNAL(triggered()), this, SLOT(viewSettings()));
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800293
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800294 // create the "change folder" action
295 m_changeFolder = new QAction(tr("&Change Folder"), this);
296 connect(m_changeFolder, SIGNAL(triggered()), this, SLOT(openFileDialog()));
Jared Lindblomb4032e22013-01-17 23:50:51 -0800297
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800298#ifdef ADHOC_SUPPORTED
299 // create "AdHoc Wifi" action
300 m_wifiAction = new QAction (tr("Enable AdHoc &WiFI"), m_trayIconMenu);
301 m_wifiAction->setChecked (false);
302 m_wifiAction->setCheckable (true);
303 connect (m_wifiAction, SIGNAL (toggled(bool)), this, SLOT(onAdHocChange(bool)));
304#endif
305
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800306#ifdef SPARKLE_SUPPORTED
Zhenkai Zhubb170d42013-02-25 13:48:59 -0800307 m_checkForUpdates = new QAction (tr("Check For Updates"), this);
308 connect (m_checkForUpdates, SIGNAL(triggered()), this, SLOT(onCheckForUpdates()));
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800309#endif
310
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800311 // create the "quit program" action
312 m_quitProgram = new QAction(tr("&Quit"), this);
313 connect(m_quitProgram, SIGNAL(triggered()), qApp, SLOT(quit()));
Jared Lindblom06405c42013-01-17 20:48:39 -0800314}
315
316void ChronoShareGui::createTrayIcon()
317{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800318 // create a new icon menu
319 m_trayIconMenu = new QMenu(this);
Jared Lindblom06405c42013-01-17 20:48:39 -0800320
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800321 // add actions to the menu
322 m_trayIconMenu->addAction(m_openFolder);
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800323 m_trayIconMenu->addAction(m_openWeb);
324 m_trayIconMenu->addMenu(m_recentFilesMenu);
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800325 m_trayIconMenu->addSeparator();
326 m_trayIconMenu->addAction(m_viewSettings);
327 m_trayIconMenu->addAction(m_changeFolder);
Alexander Afanasyeve8496a32013-03-03 16:10:43 -0800328
329#ifdef SPARKLE_SUPPORTED
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800330 m_trayIconMenu->addSeparator();
Zhenkai Zhu3857d712013-02-27 22:51:25 -0800331 m_trayIconMenu->addAction(m_checkForUpdates);
Alexander Afanasyeve8496a32013-03-03 16:10:43 -0800332#endif
333
334#ifdef ADHOC_SUPPORTED
Zhenkai Zhu3857d712013-02-27 22:51:25 -0800335 m_trayIconMenu->addSeparator();
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800336 m_trayIconMenu->addAction(m_wifiAction);
Alexander Afanasyeve8496a32013-03-03 16:10:43 -0800337#endif
338
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800339 m_trayIconMenu->addSeparator();
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800340 m_trayIconMenu->addAction(m_quitProgram);
Jared Lindblom06405c42013-01-17 20:48:39 -0800341
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800342 // create new tray icon
343 m_trayIcon = new QSystemTrayIcon(this);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800344
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800345 // associate the menu with the tray icon
346 m_trayIcon->setContextMenu(m_trayIconMenu);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800347
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800348 // handle left click of icon
349 connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconClicked(QSystemTrayIcon::ActivationReason)));
Jared Lindblom06405c42013-01-17 20:48:39 -0800350}
351
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800352void
353ChronoShareGui::onAdHocChange (bool state)
354{
355#ifdef ADHOC_SUPPORTED
356 if (m_wifiAction->isChecked ())
357 {
358 QMessageBox msgBox;
359 msgBox.setText ("WARNING: your WiFi will be disconnected");
360 msgBox.setIcon (QMessageBox::Warning);
361 msgBox.setInformativeText("AdHoc WiFi will disconnect your current WiFi.\n Are you sure that you are OK with that?");
362 msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
363 msgBox.setDefaultButton(QMessageBox::Cancel);
364 int ret = msgBox.exec();
365
366 if (ret == QMessageBox::Cancel)
367 {
368 m_wifiAction->setChecked (false);
369 }
370 else
371 {
372
373 m_wifiAction->setText (tr("Disable AdHoc WiFI"));
374
375 // create adhoc
376 m_executor.execute (Adhoc::CreateAdhoc);
377 }
378 }
379 else
380 {
381 m_wifiAction->setText (tr("Enable AdHoc WiFI"));
382
383 // disable adhoc
384 m_executor.execute (Adhoc::DestroyAdhoc);
385
386 // a trick in DestroyAdhoc ensures that WiFi will be reconnected to a default WiFi
387 }
388#endif
389}
390
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800391void
392ChronoShareGui::onCheckForUpdates()
393{
Zhenkai Zhu249fbc72013-02-27 21:50:25 -0800394#ifdef SPARKLE_SUPPORTED
Zhenkai Zhu3857d712013-02-27 22:51:25 -0800395 cout << "+++++++++++ trying to update +++++++ " << endl;
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800396 m_autoUpdate->checkForUpdates();
Zhenkai Zhu3857d712013-02-27 22:51:25 -0800397 cout << "+++++++++++ end trying to update +++++++ " << endl;
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800398#endif
Zhenkai Zhu249fbc72013-02-27 21:50:25 -0800399}
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800400
Jared Lindblom06405c42013-01-17 20:48:39 -0800401void ChronoShareGui::setIcon()
402{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800403 // set the icon image
Alexander Afanasyevcf771142013-03-19 11:15:27 -0700404 m_trayIcon->setIcon(QIcon(ICON_TRAY_FILE));
Jared Lindblom06405c42013-01-17 20:48:39 -0800405}
406
407void ChronoShareGui::openSharedFolder()
408{
Zhenkai Zhu872cc592013-03-04 14:20:46 -0800409 filesystem::path realPathToFolder (m_dirPath.toStdString ());
410 realPathToFolder /= m_sharedFolderName.toStdString ();
411 QString path = QDir::toNativeSeparators(realPathToFolder.string().c_str());
Zhenkai Zhuce04cb42013-02-25 15:29:31 -0800412 QDesktopServices::openUrl(QUrl("file:///" + path));
Jared Lindblom06405c42013-01-17 20:48:39 -0800413}
Jared Lindblomb4032e22013-01-17 23:50:51 -0800414
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800415void ChronoShareGui::openInWebBrowser()
416{
Alexander Afanasyevf63a5142013-02-28 02:21:42 -0800417 QUrl url ("http://localhost:9001/");
Alexander Afanasyevc24db642013-03-09 16:41:02 -0800418 url.setFragment ("folderHistory&"
Alexander Afanasyevf63a5142013-02-28 02:21:42 -0800419 "user=" + QUrl::toPercentEncoding (m_username) + "&"
420 "folder=" + QUrl::toPercentEncoding (m_sharedFolderName));
421
422 // i give up. there is double encoding and I have no idea how to fight it...
423 QDesktopServices::openUrl (url);
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800424}
425
426void ChronoShareGui::openFile()
427{
428 // figure out who sent the signal
429 QAction *pAction = qobject_cast<QAction*>(sender());
430 if (pAction->isEnabled())
431 {
432 // we stored full path of the file in this toolTip field
433#ifdef Q_WS_MAC
434 // we do some hack so we could show the file in Finder highlighted
435 QStringList args;
436 args << "-e";
437 args << "tell application \"Finder\"";
438 args << "-e";
439 args << "activate";
440 args << "-e";
441 args << "select POSIX file \"" + pAction->toolTip() + "/" + pAction->text() + "\"";
442 args << "-e";
443 args << "end tell";
444 QProcess::startDetached("osascript", args);
445#else
446 // too bad qt couldn't do highlighting for Linux (or Mac)
447 QDesktopServices::openUrl(QUrl("file:///" + pAction->toolTip()));
448#endif
449 }
450}
451
452void ChronoShareGui::updateRecentFilesMenu()
453{
454 for (int i = 0; i < 5; i++)
455 {
456 m_fileActions[i]->setVisible(false);
457 }
458 m_dispatcher->LookupRecentFileActions(boost::bind(&ChronoShareGui::checkFileAction, this, _1, _2, _3), 5);
459}
460
461void ChronoShareGui::checkFileAction (const std::string &filename, int action, int index)
462{
Zhenkai Zhu872cc592013-03-04 14:20:46 -0800463 filesystem::path realPathToFolder (m_dirPath.toStdString ());
464 realPathToFolder /= m_sharedFolderName.toStdString ();
465 realPathToFolder /= filename;
466 QString fullPath = realPathToFolder.string().c_str();
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800467 QFileInfo fileInfo(fullPath);
468 if (fileInfo.exists())
469 {
470 // This is a hack, we just use some field to store the path
471 m_fileActions[index]->setToolTip(fileInfo.absolutePath());
472 m_fileActions[index]->setEnabled(true);
473 }
474 else
475 {
476 // after half an hour frustrating test and search around,
477 // I think it's the problem of Qt.
478 // According to the Qt doc, the action cannot be clicked
479 // and the area would be grey, but it didn't happen
480 // User can still trigger the action, and not greyed
481 // added check in SLOT to see if the action is "enalbed"
482 // as a remedy
483 // Give up at least for now
484 m_fileActions[index]->setEnabled(false);
485 // UPDATE, file not fetched yet
486 if (action == 0)
487 {
488 QFont font;
489 // supposed by change the font, didn't happen
490 font.setWeight(QFont::Light);
491 m_fileActions[index]->setFont(font);
492 m_fileActions[index]->setToolTip(tr("Fetching..."));
493 }
494 // DELETE
495 else
496 {
497 QFont font;
498 // supposed by change the font, didn't happen
499 font.setStrikeOut(true);
500 m_fileActions[index]->setFont(font);
501 m_fileActions[index]->setToolTip(tr("Deleted..."));
502 }
503 }
504 m_fileActions[index]->setText(fileInfo.fileName());
505 m_fileActions[index]->setVisible(true);
506}
507
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800508void ChronoShareGui::changeSettings()
509{
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800510 QString oldUsername = m_username;
511 QString oldSharedFolderName = m_sharedFolderName;
512
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800513 if(!editUsername->text().isEmpty())
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -0800514 m_username = editUsername->text().trimmed();
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800515 else
516 editUsername->setText(m_username);
517
518 if(!editSharedFolder->text().isEmpty())
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -0800519 m_sharedFolderName = editSharedFolder->text().trimmed();
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800520 else
521 editSharedFolder->setText(m_sharedFolderName);
522
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800523 if (m_username.isNull () || m_username=="" ||
524 m_sharedFolderName.isNull () || m_sharedFolderName=="")
525 {
526 openMessageBox ("Error",
527 "Username and shared folder name cannot be empty");
528 }
529 else
530 {
531 saveSettings();
532 this->hide();
Zhenkai Zhud5756312013-01-31 13:49:45 -0800533
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800534 if (m_username != oldUsername ||
535 oldSharedFolderName != m_sharedFolderName)
536 {
537 startBackend (true); // restart dispatcher/fswatcher
538 }
539 }
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800540}
541
Jared Lindblomb4032e22013-01-17 23:50:51 -0800542void ChronoShareGui::openFileDialog()
543{
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800544 while (true)
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800545 {
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800546 // prompt user for new directory
547 QString tempPath = QFileDialog::getExistingDirectory(this, tr("Choose ChronoShare folder"),
548 m_dirPath, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
549 if (tempPath.isNull ())
550 {
551 if (m_dirPath.isNull ())
552 {
553 openMessageBox ("Notice", "ChronoShare will use [" + QDir::homePath () + "/ChronoShare]. \n\nYou can change it later selecting \"Change Folder\" menu.");
554
555 m_dirPath = QDir::homePath () + "/ChronoShare";
556 editSharedFolderPath->setText (m_dirPath);
557 break;
558 }
559 else
560 {
561 // user just cancelled, no need to do anything else
562 return;
563 }
564 }
565
566 QFileInfo qFileInfo (tempPath);
567
568 if (!qFileInfo.isDir())
569 {
570 openMessageBox ("Error", "Please select an existing folder or create a new one.");
571 continue;
572 }
573
574 if (m_dirPath == tempPath)
575 {
576 // user selected the same directory, no need to do anything
577 return;
578 }
579
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800580 m_dirPath = tempPath;
581 editSharedFolderPath->setText(m_dirPath);
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800582 break;
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800583 }
Jared Lindblomb4032e22013-01-17 23:50:51 -0800584
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800585 _LOG_DEBUG ("Selected path: " << m_dirPath.toStdString ());
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800586 // save settings
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800587 saveSettings ();
588
589 startBackend (true); // restart dispatcher/fswatcher
Jared Lindblomb4032e22013-01-17 23:50:51 -0800590}
591
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800592void ChronoShareGui::trayIconClicked (QSystemTrayIcon::ActivationReason reason)
Jared Lindblomb4032e22013-01-17 23:50:51 -0800593{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800594 // if double clicked, open shared folder
595 if(reason == QSystemTrayIcon::DoubleClick)
Jared Lindblomb4032e22013-01-17 23:50:51 -0800596 {
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800597 openSharedFolder();
Jared Lindblomb4032e22013-01-17 23:50:51 -0800598 }
599}
600
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800601void ChronoShareGui::viewSettings()
Jared Lindblomb4032e22013-01-17 23:50:51 -0800602{
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800603 //simple for now
604 this->show();
Zhenkai Zhud5756312013-01-31 13:49:45 -0800605 this->raise();
606 this->activateWindow();
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800607}
608
609bool ChronoShareGui::loadSettings()
610{
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800611 bool successful = true;
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800612
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800613 // Load Settings
614 // QSettings settings(m_settingsFilePath, QSettings::NativeFormat);
615 QSettings settings (QSettings::NativeFormat, QSettings::UserScope, "irl.cs.ucla.edu", "ChronoShare");
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800616
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800617 // _LOG_DEBUG (lexical_cast<string> (settings.allKeys()));
618
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800619 if(settings.contains("username"))
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800620 {
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800621 m_username = settings.value("username", "admin").toString();
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800622 }
623 else
624 {
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800625 successful = false;
626 }
627
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800628 editUsername->setText(m_username);
629
630 if(settings.contains("sharedfoldername"))
631 {
632 m_sharedFolderName = settings.value("sharedfoldername", "shared").toString();
633 }
634 else
635 {
636 successful = false;
637 }
638
639 editSharedFolder->setText(m_sharedFolderName);
640
641 if(settings.contains("dirPath"))
642 {
643 m_dirPath = settings.value("dirPath", QDir::homePath()).toString();
644 }
645 else
646 {
647 successful = false;
648 }
649
650 editSharedFolderPath->setText(m_dirPath);
651
652 _LOG_DEBUG ("Found configured path: " << (successful ? m_dirPath.toStdString () : std::string("no")));
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800653
654 return successful;
Jared Lindblomb4032e22013-01-17 23:50:51 -0800655}
656
657void ChronoShareGui::saveSettings()
658{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800659 // Save Settings
660 // QSettings settings(m_settingsFilePath, QSettings::NativeFormat);
661 QSettings settings (QSettings::NativeFormat, QSettings::UserScope, "irl.cs.ucla.edu", "ChronoShare");
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800662
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800663 settings.setValue("dirPath", m_dirPath);
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800664 settings.setValue("username", m_username);
665 settings.setValue("sharedfoldername", m_sharedFolderName);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800666}
667
668void ChronoShareGui::closeEvent(QCloseEvent* event)
669{
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800670 _LOG_DEBUG ("Close Event");
671
672 if (m_username.isNull () || m_username == "" ||
673 m_sharedFolderName.isNull () || m_sharedFolderName == "")
674 {
675 openMessageBox ("ChronoShare is not active", "Username and/or shared folder name are not set.\n\n To activate ChronoShare, open Settings menu and configure your username and shared folder name");
676 }
677
678 this->hide();
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800679 event->ignore(); // don't let the event propagate to the base class
Jared Lindblomb4032e22013-01-17 23:50:51 -0800680}
Jared Lindblomdc845f02013-01-18 17:29:40 -0800681
682#if WAF
683#include "chronosharegui.moc"
684#include "chronosharegui.cpp.moc"
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800685#endif