blob: 546fb80d42f4c1ba229ee73eae2d015238e2d906 [file] [log] [blame]
Jared Lindblom06405c42013-01-17 20:48:39 -08001/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2012-2013 University of California, Los Angeles
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Jared Lindblom <lindblom@cs.ucla.edu>
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -080019 * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
20 * Zhenkai Zhu <zhenkai@cs.ucla.edu>
21 * Ilya Moiseenko <iliamo@ucla.edu>
Jared Lindblom06405c42013-01-17 20:48:39 -080022 */
23
Alexander Afanasyevf4cde4e2016-12-25 13:42:57 -080024#include "chronosharegui.hpp"
Alexander Afanasyeve83c0562016-12-24 10:20:41 -080025#include "core/chronoshare-config.hpp"
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -080026
Alexander Afanasyevf4cde4e2016-12-25 13:42:57 -080027#include "logging.hpp"
28#include "ccnx-wrapper.hpp"
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080029#include <QValidator>
Zhenkai Zhuce04cb42013-02-25 15:29:31 -080030#include <QDir>
Zhenkai Zhu25e13582013-02-27 15:33:01 -080031#include <QFileInfo>
Zhenkai Zhuce04cb42013-02-25 15:29:31 -080032#include <QDesktopServices>
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -080033
34#include <boost/make_shared.hpp>
35
36using namespace boost;
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070037using namespace Ndnx;
Jared Lindblom06405c42013-01-17 20:48:39 -080038
Zhenkai Zhud9429222013-02-25 22:34:09 -080039static const string HTTP_SERVER_ADDRESS = "localhost";
40static const string HTTP_SERVER_PORT = "9001";
Zhenkai Zhu6b53f932013-03-02 20:46:02 -080041#ifdef _DEBUG
Zhenkai Zhu5c2475b2013-02-26 22:57:31 -080042static const string DOC_ROOT = "gui/html";
Zhenkai Zhu6b53f932013-03-02 20:46:02 -080043#else
44static const string DOC_ROOT = ":/html";
45#endif
Alexander Afanasyevcf771142013-03-19 11:15:27 -070046static const QString ICON_BIG_FILE(":/images/chronoshare-big.png");
47static const QString ICON_TRAY_FILE(":/images/" TRAY_ICON);
Zhenkai Zhud9429222013-02-25 22:34:09 -080048
Alexander Afanasyev83a53002013-01-24 11:12:01 -080049INIT_LOGGER ("Gui");
50
51ChronoShareGui::ChronoShareGui(QWidget *parent)
Jared Lindblomc8ffd592013-01-25 00:00:30 -080052 : QDialog(parent)
Zhenkai Zhud5756312013-01-31 13:49:45 -080053 , m_watcher(0)
54 , m_dispatcher(0)
Zhenkai Zhud9429222013-02-25 22:34:09 -080055 , m_httpServer(0)
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -080056#ifdef ADHOC_SUPPORTED
57 , m_executor (1)
58#endif
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -080059#ifdef SPARKLE_SUPPORTED
Zhenkai Zhu8e3e9072013-02-28 15:40:51 -080060 , m_autoUpdate(new SparkleAutoUpdate(tr("http://irl.cs.ucla.edu/~zhenkai/chronoshare_dist/chronoshare.xml")))
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -080061#endif
Jared Lindblom06405c42013-01-17 20:48:39 -080062{
Jared Lindblomf4b900e2013-02-07 18:08:47 -080063 setWindowTitle("Settings");
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -080064 setMinimumWidth (600);
Jared Lindblomc8ffd592013-01-25 00:00:30 -080065
Jared Lindblomd8b76ad2013-02-07 20:37:37 -080066 labelUsername = new QLabel("Username (hint: /<username>)");
Jared Lindblomc8ffd592013-01-25 00:00:30 -080067 labelSharedFolder = new QLabel("Shared Folder Name");
68 labelSharedFolderPath = new QLabel("Shared Folder Path");
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080069
Zhenkai Zhud5756312013-01-31 13:49:45 -080070 QRegExp regex("(/[^/]+)+$");
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080071 QValidator *prefixValidator = new QRegExpValidator(regex, this);
72
Jared Lindblomc8ffd592013-01-25 00:00:30 -080073 editUsername = new QLineEdit();
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080074 editUsername->setValidator(prefixValidator);
75
76 QRegExp noPureWhiteSpace("^\\S+.*$");
77 QValidator *wsValidator = new QRegExpValidator(noPureWhiteSpace, this);
Jared Lindblomc8ffd592013-01-25 00:00:30 -080078 editSharedFolder = new QLineEdit();
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080079 editSharedFolder->setValidator(wsValidator);
80
Jared Lindblomc8ffd592013-01-25 00:00:30 -080081 editSharedFolderPath = new QLineEdit();
82 editSharedFolderPath->setReadOnly(true);
83 QPalette pal = editSharedFolderPath->palette();
84 pal.setColor(QPalette::Active, QPalette::Base, pal.color(QPalette::Disabled, QPalette::Base));
85 editSharedFolderPath->setPalette(pal);
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -080086 button = new QPushButton("Save and apply settings");
Zhenkai Zhu630d0f12013-02-28 17:21:54 -080087
88 QString versionString = QString("Version: ChronoShare v%1").arg(CHRONOSHARE_VERSION);
89 label = new QLabel(versionString, this);
Jared Lindblomc8ffd592013-01-25 00:00:30 -080090
91 connect(button, SIGNAL(clicked()), this, SLOT(changeSettings()));
92
93 mainLayout = new QVBoxLayout; //vertically
94 mainLayout->addWidget(labelUsername);
95 mainLayout->addWidget(editUsername);
96 mainLayout->addWidget(labelSharedFolder);
97 mainLayout->addWidget(editSharedFolder);
98 mainLayout->addWidget(labelSharedFolderPath);
99 mainLayout->addWidget(editSharedFolderPath);
100 mainLayout->addWidget(button);
101 mainLayout->addWidget(label);
102 setLayout(mainLayout);
103
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800104 // create actions that result from clicking a menu option
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800105 createActionsAndMenu();
Jared Lindblomb4032e22013-01-17 23:50:51 -0800106
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800107 // create tray icon
108 createTrayIcon();
Jared Lindblomb4032e22013-01-17 23:50:51 -0800109
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800110 // set icon image
111 setIcon();
Jared Lindblom06405c42013-01-17 20:48:39 -0800112
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800113 // show tray icon
114 m_trayIcon->show();
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800115
Zhenkai Zhud5756312013-01-31 13:49:45 -0800116 // load settings
117 if(!loadSettings())
118 {
119 // prompt user to choose folder
120 openMessageBox("First Time Setup", "Please enter a username, shared folder name and choose the shared folder path on your local filesystem.");
121 viewSettings();
122 openFileDialog();
123 viewSettings();
124 }
125 else
126 {
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800127 if (m_username.isNull () || m_username == "" ||
128 m_sharedFolderName.isNull () || m_sharedFolderName == "")
129 {
130 openMessageBox("First Time Setup", "To activate ChronoShare, please configure your username and shared folder name.");
131 viewSettings();
132 }
133 else
134 {
135 startBackend();
136 }
Zhenkai Zhud5756312013-01-31 13:49:45 -0800137 }
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800138
139#ifdef ADHOC_SUPPORTED
140 m_executor.start ();
141#endif
Zhenkai Zhud5756312013-01-31 13:49:45 -0800142}
143
144void
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800145ChronoShareGui::startBackend (bool restart/*=false*/)
Zhenkai Zhud5756312013-01-31 13:49:45 -0800146{
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800147 if (m_username.isNull () || m_username=="" ||
148 m_sharedFolderName.isNull () || m_sharedFolderName=="" ||
149 m_dirPath.isNull () || m_dirPath=="")
150 {
151 _LOG_DEBUG ("Don't start backend, because settings are in progress or incomplete");
152 return;
153 }
154
Zhenkai Zhud5756312013-01-31 13:49:45 -0800155 if (m_watcher != 0 && m_dispatcher != 0)
156 {
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800157 if (!restart)
158 {
159 return;
160 }
161
162 _LOG_DEBUG ("Restarting Dispatcher and FileWatcher for the new location or new username");
163 delete m_watcher; // stop filewatching ASAP
164 delete m_dispatcher; // stop dispatcher ASAP, but after watcher (to prevent triggering callbacks on deleted object)
Zhenkai Zhud5756312013-01-31 13:49:45 -0800165 }
166
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800167 filesystem::path realPathToFolder (m_dirPath.toStdString ());
168 realPathToFolder /= m_sharedFolderName.toStdString ();
169
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -0800170 m_dispatcher = new Dispatcher (m_username.toStdString (), m_sharedFolderName.toStdString (),
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700171 realPathToFolder, make_shared<NdnxWrapper> ());
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800172
173 // Alex: this **must** be here, otherwise m_dirPath will be uninitialized
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800174 m_watcher = new FsWatcher (realPathToFolder.string ().c_str (),
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -0800175 bind (&Dispatcher::Did_LocalFile_AddOrModify, m_dispatcher, _1),
Zhenkai Zhud1756272013-02-01 17:02:18 -0800176 bind (&Dispatcher::Did_LocalFile_Delete, m_dispatcher, _1));
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800177
178 if (m_httpServer != 0)
179 {
180 // no need to restart webserver if it already exists
181 return;
182 }
183
Zhenkai Zhud9429222013-02-25 22:34:09 -0800184 QFileInfo indexHtmlInfo(":/html/index.html");
185 if (indexHtmlInfo.exists())
186 {
Zhenkai Zhu8da33652013-03-04 10:52:03 -0800187 try
188 {
189 m_httpServer = new http::server::server(HTTP_SERVER_ADDRESS, HTTP_SERVER_PORT, DOC_ROOT);
190 m_httpServerThread = boost::thread(&http::server::server::run, m_httpServer);
191 }
192 catch (std::exception &e)
193 {
194 _LOG_ERROR ("Start http server failed");
195 m_httpServer = 0; // just to make sure
196 QMessageBox msgBox;
197 msgBox.setText ("WARNING: Cannot start http server!");
198 msgBox.setIcon (QMessageBox::Warning);
199 msgBox.setInformativeText(QString("Starting http server failed. You will not be able to check history from web brower. Exception caused: %1").arg(e.what()));
200 msgBox.setStandardButtons(QMessageBox::Ok);
201 msgBox.exec();
202 }
Zhenkai Zhud9429222013-02-25 22:34:09 -0800203 }
204 else
205 {
206 _LOG_ERROR ("Http server doc root dir does not exist!");
Zhenkai Zhud9429222013-02-25 22:34:09 -0800207 }
Jared Lindblom06405c42013-01-17 20:48:39 -0800208}
209
210ChronoShareGui::~ChronoShareGui()
211{
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800212#ifdef ADHOC_SUPPORTED
213 m_executor.shutdown ();
214#endif
215
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800216 delete m_watcher; // stop filewatching ASAP
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -0800217 delete m_dispatcher; // stop dispatcher ASAP, but after watcher (to prevent triggering callbacks on deleted object)
Zhenkai Zhu8da33652013-03-04 10:52:03 -0800218 if (m_httpServer != 0)
219 {
220 m_httpServer->handle_stop();
221 m_httpServerThread.join();
222 delete m_httpServer;
223 }
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800224
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800225 // cleanup
226 delete m_trayIcon;
227 delete m_trayIconMenu;
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800228#ifdef ADHOC_SUPPORTED
229 delete m_wifiAction;
230#endif
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800231#ifdef SPARKLE_SUPPORTED
232 delete m_autoUpdate;
Zhenkai Zhubb170d42013-02-25 13:48:59 -0800233 delete m_checkForUpdates;
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800234#endif
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800235 delete m_openFolder;
236 delete m_viewSettings;
237 delete m_changeFolder;
238 delete m_quitProgram;
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800239
240 delete labelUsername;
241 delete labelSharedFolder;
242 delete editUsername;
243 delete editSharedFolder;
244 delete button;
245 delete label;
246 delete mainLayout;
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800247}
248
249void ChronoShareGui::openMessageBox(QString title, QString text)
250{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800251 QMessageBox messageBox(this);
252 messageBox.setWindowTitle(title);
253 messageBox.setText(text);
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800254
Alexander Afanasyevcf771142013-03-19 11:15:27 -0700255 messageBox.setIconPixmap(QPixmap(ICON_BIG_FILE));
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800256
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800257 messageBox.exec();
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800258}
259
260void ChronoShareGui::openMessageBox(QString title, QString text, QString infotext)
261{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800262 QMessageBox messageBox(this);
263 messageBox.setWindowTitle(title);
264 messageBox.setText(text);
265 messageBox.setInformativeText(infotext);
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800266
Alexander Afanasyevcf771142013-03-19 11:15:27 -0700267 messageBox.setIconPixmap(QPixmap(ICON_BIG_FILE));
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800268
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800269 messageBox.exec();
Jared Lindblom06405c42013-01-17 20:48:39 -0800270}
271
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800272void ChronoShareGui::createActionsAndMenu()
Jared Lindblom06405c42013-01-17 20:48:39 -0800273{
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800274 _LOG_DEBUG ("Create actions");
275
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800276 // create the "open folder" action
277 m_openFolder = new QAction(tr("&Open Folder"), this);
278 connect(m_openFolder, SIGNAL(triggered()), this, SLOT(openSharedFolder()));
Jared Lindblom06405c42013-01-17 20:48:39 -0800279
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800280 m_openWeb = new QAction(tr("Open in &Browser"), this);
281 connect(m_openWeb, SIGNAL(triggered()), this, SLOT(openInWebBrowser()));
282
283 m_recentFilesMenu = new QMenu(tr("Recently Changed Files"), this);
284 for (int i = 0; i < 5; i++)
285 {
286 m_fileActions[i] = new QAction(this);
287 m_fileActions[i]->setVisible(false);
288 connect(m_fileActions[i], SIGNAL(triggered()), this, SLOT(openFile()));
289 m_recentFilesMenu->addAction(m_fileActions[i]);
290 }
291 connect(m_recentFilesMenu, SIGNAL(aboutToShow()), this, SLOT(updateRecentFilesMenu()));
292
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800293 // create the "view settings" action
294 m_viewSettings = new QAction(tr("&View Settings"), this);
295 connect(m_viewSettings, SIGNAL(triggered()), this, SLOT(viewSettings()));
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800296
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800297 // create the "change folder" action
298 m_changeFolder = new QAction(tr("&Change Folder"), this);
299 connect(m_changeFolder, SIGNAL(triggered()), this, SLOT(openFileDialog()));
Jared Lindblomb4032e22013-01-17 23:50:51 -0800300
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800301#ifdef ADHOC_SUPPORTED
302 // create "AdHoc Wifi" action
303 m_wifiAction = new QAction (tr("Enable AdHoc &WiFI"), m_trayIconMenu);
304 m_wifiAction->setChecked (false);
305 m_wifiAction->setCheckable (true);
306 connect (m_wifiAction, SIGNAL (toggled(bool)), this, SLOT(onAdHocChange(bool)));
307#endif
308
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800309#ifdef SPARKLE_SUPPORTED
Zhenkai Zhubb170d42013-02-25 13:48:59 -0800310 m_checkForUpdates = new QAction (tr("Check For Updates"), this);
311 connect (m_checkForUpdates, SIGNAL(triggered()), this, SLOT(onCheckForUpdates()));
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800312#endif
313
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800314 // create the "quit program" action
315 m_quitProgram = new QAction(tr("&Quit"), this);
316 connect(m_quitProgram, SIGNAL(triggered()), qApp, SLOT(quit()));
Jared Lindblom06405c42013-01-17 20:48:39 -0800317}
318
319void ChronoShareGui::createTrayIcon()
320{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800321 // create a new icon menu
322 m_trayIconMenu = new QMenu(this);
Jared Lindblom06405c42013-01-17 20:48:39 -0800323
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800324 // add actions to the menu
325 m_trayIconMenu->addAction(m_openFolder);
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800326 m_trayIconMenu->addAction(m_openWeb);
327 m_trayIconMenu->addMenu(m_recentFilesMenu);
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800328 m_trayIconMenu->addSeparator();
329 m_trayIconMenu->addAction(m_viewSettings);
330 m_trayIconMenu->addAction(m_changeFolder);
Alexander Afanasyeve8496a32013-03-03 16:10:43 -0800331
332#ifdef SPARKLE_SUPPORTED
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800333 m_trayIconMenu->addSeparator();
Zhenkai Zhu3857d712013-02-27 22:51:25 -0800334 m_trayIconMenu->addAction(m_checkForUpdates);
Alexander Afanasyeve8496a32013-03-03 16:10:43 -0800335#endif
336
337#ifdef ADHOC_SUPPORTED
Zhenkai Zhu3857d712013-02-27 22:51:25 -0800338 m_trayIconMenu->addSeparator();
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800339 m_trayIconMenu->addAction(m_wifiAction);
Alexander Afanasyeve8496a32013-03-03 16:10:43 -0800340#endif
341
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800342 m_trayIconMenu->addSeparator();
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800343 m_trayIconMenu->addAction(m_quitProgram);
Jared Lindblom06405c42013-01-17 20:48:39 -0800344
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800345 // create new tray icon
346 m_trayIcon = new QSystemTrayIcon(this);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800347
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800348 // associate the menu with the tray icon
349 m_trayIcon->setContextMenu(m_trayIconMenu);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800350
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800351 // handle left click of icon
352 connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconClicked(QSystemTrayIcon::ActivationReason)));
Jared Lindblom06405c42013-01-17 20:48:39 -0800353}
354
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800355void
356ChronoShareGui::onAdHocChange (bool state)
357{
358#ifdef ADHOC_SUPPORTED
359 if (m_wifiAction->isChecked ())
360 {
361 QMessageBox msgBox;
362 msgBox.setText ("WARNING: your WiFi will be disconnected");
363 msgBox.setIcon (QMessageBox::Warning);
364 msgBox.setInformativeText("AdHoc WiFi will disconnect your current WiFi.\n Are you sure that you are OK with that?");
365 msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
366 msgBox.setDefaultButton(QMessageBox::Cancel);
367 int ret = msgBox.exec();
368
369 if (ret == QMessageBox::Cancel)
370 {
371 m_wifiAction->setChecked (false);
372 }
373 else
374 {
375
376 m_wifiAction->setText (tr("Disable AdHoc WiFI"));
377
378 // create adhoc
379 m_executor.execute (Adhoc::CreateAdhoc);
380 }
381 }
382 else
383 {
384 m_wifiAction->setText (tr("Enable AdHoc WiFI"));
385
386 // disable adhoc
387 m_executor.execute (Adhoc::DestroyAdhoc);
388
389 // a trick in DestroyAdhoc ensures that WiFi will be reconnected to a default WiFi
390 }
391#endif
392}
393
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800394void
395ChronoShareGui::onCheckForUpdates()
396{
Zhenkai Zhu249fbc72013-02-27 21:50:25 -0800397#ifdef SPARKLE_SUPPORTED
Zhenkai Zhu3857d712013-02-27 22:51:25 -0800398 cout << "+++++++++++ trying to update +++++++ " << endl;
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800399 m_autoUpdate->checkForUpdates();
Zhenkai Zhu3857d712013-02-27 22:51:25 -0800400 cout << "+++++++++++ end trying to update +++++++ " << endl;
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800401#endif
Zhenkai Zhu249fbc72013-02-27 21:50:25 -0800402}
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800403
Jared Lindblom06405c42013-01-17 20:48:39 -0800404void ChronoShareGui::setIcon()
405{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800406 // set the icon image
Alexander Afanasyevcf771142013-03-19 11:15:27 -0700407 m_trayIcon->setIcon(QIcon(ICON_TRAY_FILE));
Jared Lindblom06405c42013-01-17 20:48:39 -0800408}
409
410void ChronoShareGui::openSharedFolder()
411{
Zhenkai Zhu872cc592013-03-04 14:20:46 -0800412 filesystem::path realPathToFolder (m_dirPath.toStdString ());
413 realPathToFolder /= m_sharedFolderName.toStdString ();
414 QString path = QDir::toNativeSeparators(realPathToFolder.string().c_str());
Zhenkai Zhuce04cb42013-02-25 15:29:31 -0800415 QDesktopServices::openUrl(QUrl("file:///" + path));
Jared Lindblom06405c42013-01-17 20:48:39 -0800416}
Jared Lindblomb4032e22013-01-17 23:50:51 -0800417
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800418void ChronoShareGui::openInWebBrowser()
419{
Alexander Afanasyevf63a5142013-02-28 02:21:42 -0800420 QUrl url ("http://localhost:9001/");
Alexander Afanasyevc24db642013-03-09 16:41:02 -0800421 url.setFragment ("folderHistory&"
Alexander Afanasyevf63a5142013-02-28 02:21:42 -0800422 "user=" + QUrl::toPercentEncoding (m_username) + "&"
423 "folder=" + QUrl::toPercentEncoding (m_sharedFolderName));
424
425 // i give up. there is double encoding and I have no idea how to fight it...
426 QDesktopServices::openUrl (url);
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800427}
428
429void ChronoShareGui::openFile()
430{
431 // figure out who sent the signal
432 QAction *pAction = qobject_cast<QAction*>(sender());
433 if (pAction->isEnabled())
434 {
435 // we stored full path of the file in this toolTip field
436#ifdef Q_WS_MAC
437 // we do some hack so we could show the file in Finder highlighted
438 QStringList args;
439 args << "-e";
440 args << "tell application \"Finder\"";
441 args << "-e";
442 args << "activate";
443 args << "-e";
444 args << "select POSIX file \"" + pAction->toolTip() + "/" + pAction->text() + "\"";
445 args << "-e";
446 args << "end tell";
447 QProcess::startDetached("osascript", args);
448#else
449 // too bad qt couldn't do highlighting for Linux (or Mac)
450 QDesktopServices::openUrl(QUrl("file:///" + pAction->toolTip()));
451#endif
452 }
453}
454
455void ChronoShareGui::updateRecentFilesMenu()
456{
457 for (int i = 0; i < 5; i++)
458 {
459 m_fileActions[i]->setVisible(false);
460 }
461 m_dispatcher->LookupRecentFileActions(boost::bind(&ChronoShareGui::checkFileAction, this, _1, _2, _3), 5);
462}
463
464void ChronoShareGui::checkFileAction (const std::string &filename, int action, int index)
465{
Zhenkai Zhu872cc592013-03-04 14:20:46 -0800466 filesystem::path realPathToFolder (m_dirPath.toStdString ());
467 realPathToFolder /= m_sharedFolderName.toStdString ();
468 realPathToFolder /= filename;
469 QString fullPath = realPathToFolder.string().c_str();
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800470 QFileInfo fileInfo(fullPath);
471 if (fileInfo.exists())
472 {
473 // This is a hack, we just use some field to store the path
474 m_fileActions[index]->setToolTip(fileInfo.absolutePath());
475 m_fileActions[index]->setEnabled(true);
476 }
477 else
478 {
479 // after half an hour frustrating test and search around,
480 // I think it's the problem of Qt.
481 // According to the Qt doc, the action cannot be clicked
482 // and the area would be grey, but it didn't happen
483 // User can still trigger the action, and not greyed
484 // added check in SLOT to see if the action is "enalbed"
485 // as a remedy
486 // Give up at least for now
487 m_fileActions[index]->setEnabled(false);
488 // UPDATE, file not fetched yet
489 if (action == 0)
490 {
491 QFont font;
492 // supposed by change the font, didn't happen
493 font.setWeight(QFont::Light);
494 m_fileActions[index]->setFont(font);
495 m_fileActions[index]->setToolTip(tr("Fetching..."));
496 }
497 // DELETE
498 else
499 {
500 QFont font;
501 // supposed by change the font, didn't happen
502 font.setStrikeOut(true);
503 m_fileActions[index]->setFont(font);
504 m_fileActions[index]->setToolTip(tr("Deleted..."));
505 }
506 }
507 m_fileActions[index]->setText(fileInfo.fileName());
508 m_fileActions[index]->setVisible(true);
509}
510
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800511void ChronoShareGui::changeSettings()
512{
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800513 QString oldUsername = m_username;
514 QString oldSharedFolderName = m_sharedFolderName;
515
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800516 if(!editUsername->text().isEmpty())
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -0800517 m_username = editUsername->text().trimmed();
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800518 else
519 editUsername->setText(m_username);
520
521 if(!editSharedFolder->text().isEmpty())
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -0800522 m_sharedFolderName = editSharedFolder->text().trimmed();
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800523 else
524 editSharedFolder->setText(m_sharedFolderName);
525
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800526 if (m_username.isNull () || m_username=="" ||
527 m_sharedFolderName.isNull () || m_sharedFolderName=="")
528 {
529 openMessageBox ("Error",
530 "Username and shared folder name cannot be empty");
531 }
532 else
533 {
534 saveSettings();
535 this->hide();
Zhenkai Zhud5756312013-01-31 13:49:45 -0800536
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800537 if (m_username != oldUsername ||
538 oldSharedFolderName != m_sharedFolderName)
539 {
540 startBackend (true); // restart dispatcher/fswatcher
541 }
542 }
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800543}
544
Jared Lindblomb4032e22013-01-17 23:50:51 -0800545void ChronoShareGui::openFileDialog()
546{
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800547 while (true)
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800548 {
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800549 // prompt user for new directory
550 QString tempPath = QFileDialog::getExistingDirectory(this, tr("Choose ChronoShare folder"),
551 m_dirPath, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
552 if (tempPath.isNull ())
553 {
554 if (m_dirPath.isNull ())
555 {
556 openMessageBox ("Notice", "ChronoShare will use [" + QDir::homePath () + "/ChronoShare]. \n\nYou can change it later selecting \"Change Folder\" menu.");
557
558 m_dirPath = QDir::homePath () + "/ChronoShare";
559 editSharedFolderPath->setText (m_dirPath);
560 break;
561 }
562 else
563 {
564 // user just cancelled, no need to do anything else
565 return;
566 }
567 }
568
569 QFileInfo qFileInfo (tempPath);
570
571 if (!qFileInfo.isDir())
572 {
573 openMessageBox ("Error", "Please select an existing folder or create a new one.");
574 continue;
575 }
576
577 if (m_dirPath == tempPath)
578 {
579 // user selected the same directory, no need to do anything
580 return;
581 }
582
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800583 m_dirPath = tempPath;
584 editSharedFolderPath->setText(m_dirPath);
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800585 break;
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800586 }
Jared Lindblomb4032e22013-01-17 23:50:51 -0800587
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800588 _LOG_DEBUG ("Selected path: " << m_dirPath.toStdString ());
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800589 // save settings
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800590 saveSettings ();
591
592 startBackend (true); // restart dispatcher/fswatcher
Jared Lindblomb4032e22013-01-17 23:50:51 -0800593}
594
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800595void ChronoShareGui::trayIconClicked (QSystemTrayIcon::ActivationReason reason)
Jared Lindblomb4032e22013-01-17 23:50:51 -0800596{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800597 // if double clicked, open shared folder
598 if(reason == QSystemTrayIcon::DoubleClick)
Jared Lindblomb4032e22013-01-17 23:50:51 -0800599 {
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800600 openSharedFolder();
Jared Lindblomb4032e22013-01-17 23:50:51 -0800601 }
602}
603
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800604void ChronoShareGui::viewSettings()
Jared Lindblomb4032e22013-01-17 23:50:51 -0800605{
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800606 //simple for now
607 this->show();
Zhenkai Zhud5756312013-01-31 13:49:45 -0800608 this->raise();
609 this->activateWindow();
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800610}
611
612bool ChronoShareGui::loadSettings()
613{
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800614 bool successful = true;
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800615
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800616 // Load Settings
617 // QSettings settings(m_settingsFilePath, QSettings::NativeFormat);
618 QSettings settings (QSettings::NativeFormat, QSettings::UserScope, "irl.cs.ucla.edu", "ChronoShare");
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800619
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800620 // _LOG_DEBUG (lexical_cast<string> (settings.allKeys()));
621
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800622 if(settings.contains("username"))
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800623 {
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800624 m_username = settings.value("username", "admin").toString();
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800625 }
626 else
627 {
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800628 successful = false;
629 }
630
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800631 editUsername->setText(m_username);
632
633 if(settings.contains("sharedfoldername"))
634 {
635 m_sharedFolderName = settings.value("sharedfoldername", "shared").toString();
636 }
637 else
638 {
639 successful = false;
640 }
641
642 editSharedFolder->setText(m_sharedFolderName);
643
644 if(settings.contains("dirPath"))
645 {
646 m_dirPath = settings.value("dirPath", QDir::homePath()).toString();
647 }
648 else
649 {
650 successful = false;
651 }
652
653 editSharedFolderPath->setText(m_dirPath);
654
655 _LOG_DEBUG ("Found configured path: " << (successful ? m_dirPath.toStdString () : std::string("no")));
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800656
657 return successful;
Jared Lindblomb4032e22013-01-17 23:50:51 -0800658}
659
660void ChronoShareGui::saveSettings()
661{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800662 // Save Settings
663 // QSettings settings(m_settingsFilePath, QSettings::NativeFormat);
664 QSettings settings (QSettings::NativeFormat, QSettings::UserScope, "irl.cs.ucla.edu", "ChronoShare");
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800665
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800666 settings.setValue("dirPath", m_dirPath);
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800667 settings.setValue("username", m_username);
668 settings.setValue("sharedfoldername", m_sharedFolderName);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800669}
670
671void ChronoShareGui::closeEvent(QCloseEvent* event)
672{
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800673 _LOG_DEBUG ("Close Event");
674
675 if (m_username.isNull () || m_username == "" ||
676 m_sharedFolderName.isNull () || m_sharedFolderName == "")
677 {
678 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");
679 }
680
681 this->hide();
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800682 event->ignore(); // don't let the event propagate to the base class
Jared Lindblomb4032e22013-01-17 23:50:51 -0800683}
Jared Lindblomdc845f02013-01-18 17:29:40 -0800684
685#if WAF
686#include "chronosharegui.moc"
687#include "chronosharegui.cpp.moc"
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800688#endif