blob: 2901cddb3a1f917ca001070d68a7abaafce20ff9 [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
24#include "chronosharegui.h"
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -080025
Alexander Afanasyev83a53002013-01-24 11:12:01 -080026#include "logging.h"
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -080027#include "ccnx-wrapper.h"
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080028#include <QValidator>
Zhenkai Zhuce04cb42013-02-25 15:29:31 -080029#include <QDir>
Zhenkai Zhu25e13582013-02-27 15:33:01 -080030#include <QFileInfo>
Zhenkai Zhuce04cb42013-02-25 15:29:31 -080031#include <QDesktopServices>
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -080032
33#include <boost/make_shared.hpp>
34
35using namespace boost;
36using namespace Ccnx;
Jared Lindblom06405c42013-01-17 20:48:39 -080037
Zhenkai Zhud9429222013-02-25 22:34:09 -080038static const string HTTP_SERVER_ADDRESS = "localhost";
39static const string HTTP_SERVER_PORT = "9001";
Zhenkai Zhu6b53f932013-03-02 20:46:02 -080040#ifdef _DEBUG
Zhenkai Zhu5c2475b2013-02-26 22:57:31 -080041static const string DOC_ROOT = "gui/html";
Zhenkai Zhu6b53f932013-03-02 20:46:02 -080042#else
43static const string DOC_ROOT = ":/html";
44#endif
Zhenkai Zhud9429222013-02-25 22:34:09 -080045static const QString ICON_PICTURE_QSTRING(":/images/friends-group-icon.png");
46
Alexander Afanasyev83a53002013-01-24 11:12:01 -080047INIT_LOGGER ("Gui");
48
49ChronoShareGui::ChronoShareGui(QWidget *parent)
Jared Lindblomc8ffd592013-01-25 00:00:30 -080050 : QDialog(parent)
Zhenkai Zhud5756312013-01-31 13:49:45 -080051 , m_watcher(0)
52 , m_dispatcher(0)
Zhenkai Zhud9429222013-02-25 22:34:09 -080053 , m_httpServer(0)
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -080054#ifdef ADHOC_SUPPORTED
55 , m_executor (1)
56#endif
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -080057#ifdef SPARKLE_SUPPORTED
Zhenkai Zhu8e3e9072013-02-28 15:40:51 -080058 , m_autoUpdate(new SparkleAutoUpdate(tr("http://irl.cs.ucla.edu/~zhenkai/chronoshare_dist/chronoshare.xml")))
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -080059#endif
Jared Lindblom06405c42013-01-17 20:48:39 -080060{
Jared Lindblomf4b900e2013-02-07 18:08:47 -080061 setWindowTitle("Settings");
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -080062 setMinimumWidth (600);
Jared Lindblomc8ffd592013-01-25 00:00:30 -080063
Jared Lindblomd8b76ad2013-02-07 20:37:37 -080064 labelUsername = new QLabel("Username (hint: /<username>)");
Jared Lindblomc8ffd592013-01-25 00:00:30 -080065 labelSharedFolder = new QLabel("Shared Folder Name");
66 labelSharedFolderPath = new QLabel("Shared Folder Path");
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080067
Zhenkai Zhud5756312013-01-31 13:49:45 -080068 QRegExp regex("(/[^/]+)+$");
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080069 QValidator *prefixValidator = new QRegExpValidator(regex, this);
70
Jared Lindblomc8ffd592013-01-25 00:00:30 -080071 editUsername = new QLineEdit();
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080072 editUsername->setValidator(prefixValidator);
73
74 QRegExp noPureWhiteSpace("^\\S+.*$");
75 QValidator *wsValidator = new QRegExpValidator(noPureWhiteSpace, this);
Jared Lindblomc8ffd592013-01-25 00:00:30 -080076 editSharedFolder = new QLineEdit();
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080077 editSharedFolder->setValidator(wsValidator);
78
Jared Lindblomc8ffd592013-01-25 00:00:30 -080079 editSharedFolderPath = new QLineEdit();
80 editSharedFolderPath->setReadOnly(true);
81 QPalette pal = editSharedFolderPath->palette();
82 pal.setColor(QPalette::Active, QPalette::Base, pal.color(QPalette::Disabled, QPalette::Base));
83 editSharedFolderPath->setPalette(pal);
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -080084 button = new QPushButton("Save and apply settings");
Zhenkai Zhu630d0f12013-02-28 17:21:54 -080085
86 QString versionString = QString("Version: ChronoShare v%1").arg(CHRONOSHARE_VERSION);
87 label = new QLabel(versionString, this);
Jared Lindblomc8ffd592013-01-25 00:00:30 -080088
89 connect(button, SIGNAL(clicked()), this, SLOT(changeSettings()));
90
91 mainLayout = new QVBoxLayout; //vertically
92 mainLayout->addWidget(labelUsername);
93 mainLayout->addWidget(editUsername);
94 mainLayout->addWidget(labelSharedFolder);
95 mainLayout->addWidget(editSharedFolder);
96 mainLayout->addWidget(labelSharedFolderPath);
97 mainLayout->addWidget(editSharedFolderPath);
98 mainLayout->addWidget(button);
99 mainLayout->addWidget(label);
100 setLayout(mainLayout);
101
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800102 // create actions that result from clicking a menu option
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800103 createActionsAndMenu();
Jared Lindblomb4032e22013-01-17 23:50:51 -0800104
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800105 // create tray icon
106 createTrayIcon();
Jared Lindblomb4032e22013-01-17 23:50:51 -0800107
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800108 // set icon image
109 setIcon();
Jared Lindblom06405c42013-01-17 20:48:39 -0800110
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800111 // show tray icon
112 m_trayIcon->show();
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800113
Zhenkai Zhud5756312013-01-31 13:49:45 -0800114 // load settings
115 if(!loadSettings())
116 {
117 // prompt user to choose folder
118 openMessageBox("First Time Setup", "Please enter a username, shared folder name and choose the shared folder path on your local filesystem.");
119 viewSettings();
120 openFileDialog();
121 viewSettings();
122 }
123 else
124 {
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800125 if (m_username.isNull () || m_username == "" ||
126 m_sharedFolderName.isNull () || m_sharedFolderName == "")
127 {
128 openMessageBox("First Time Setup", "To activate ChronoShare, please configure your username and shared folder name.");
129 viewSettings();
130 }
131 else
132 {
133 startBackend();
134 }
Zhenkai Zhud5756312013-01-31 13:49:45 -0800135 }
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800136
137#ifdef ADHOC_SUPPORTED
138 m_executor.start ();
139#endif
Zhenkai Zhud5756312013-01-31 13:49:45 -0800140}
141
142void
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800143ChronoShareGui::startBackend (bool restart/*=false*/)
Zhenkai Zhud5756312013-01-31 13:49:45 -0800144{
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800145 if (m_username.isNull () || m_username=="" ||
146 m_sharedFolderName.isNull () || m_sharedFolderName=="" ||
147 m_dirPath.isNull () || m_dirPath=="")
148 {
149 _LOG_DEBUG ("Don't start backend, because settings are in progress or incomplete");
150 return;
151 }
152
Zhenkai Zhud5756312013-01-31 13:49:45 -0800153 if (m_watcher != 0 && m_dispatcher != 0)
154 {
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800155 if (!restart)
156 {
157 return;
158 }
159
160 _LOG_DEBUG ("Restarting Dispatcher and FileWatcher for the new location or new username");
161 delete m_watcher; // stop filewatching ASAP
162 delete m_dispatcher; // stop dispatcher ASAP, but after watcher (to prevent triggering callbacks on deleted object)
Zhenkai Zhud5756312013-01-31 13:49:45 -0800163 }
164
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800165 filesystem::path realPathToFolder (m_dirPath.toStdString ());
166 realPathToFolder /= m_sharedFolderName.toStdString ();
167
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -0800168 m_dispatcher = new Dispatcher (m_username.toStdString (), m_sharedFolderName.toStdString (),
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800169 realPathToFolder, make_shared<CcnxWrapper> ());
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800170
171 // Alex: this **must** be here, otherwise m_dirPath will be uninitialized
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800172 m_watcher = new FsWatcher (realPathToFolder.string ().c_str (),
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -0800173 bind (&Dispatcher::Did_LocalFile_AddOrModify, m_dispatcher, _1),
Zhenkai Zhud1756272013-02-01 17:02:18 -0800174 bind (&Dispatcher::Did_LocalFile_Delete, m_dispatcher, _1));
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800175
176 if (m_httpServer != 0)
177 {
178 // no need to restart webserver if it already exists
179 return;
180 }
181
Zhenkai Zhud9429222013-02-25 22:34:09 -0800182 QFileInfo indexHtmlInfo(":/html/index.html");
183 if (indexHtmlInfo.exists())
184 {
Zhenkai Zhu8da33652013-03-04 10:52:03 -0800185 try
186 {
187 m_httpServer = new http::server::server(HTTP_SERVER_ADDRESS, HTTP_SERVER_PORT, DOC_ROOT);
188 m_httpServerThread = boost::thread(&http::server::server::run, m_httpServer);
189 }
190 catch (std::exception &e)
191 {
192 _LOG_ERROR ("Start http server failed");
193 m_httpServer = 0; // just to make sure
194 QMessageBox msgBox;
195 msgBox.setText ("WARNING: Cannot start http server!");
196 msgBox.setIcon (QMessageBox::Warning);
197 msgBox.setInformativeText(QString("Starting http server failed. You will not be able to check history from web brower. Exception caused: %1").arg(e.what()));
198 msgBox.setStandardButtons(QMessageBox::Ok);
199 msgBox.exec();
200 }
Zhenkai Zhud9429222013-02-25 22:34:09 -0800201 }
202 else
203 {
204 _LOG_ERROR ("Http server doc root dir does not exist!");
Zhenkai Zhud9429222013-02-25 22:34:09 -0800205 }
Jared Lindblom06405c42013-01-17 20:48:39 -0800206}
207
208ChronoShareGui::~ChronoShareGui()
209{
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800210#ifdef ADHOC_SUPPORTED
211 m_executor.shutdown ();
212#endif
213
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800214 delete m_watcher; // stop filewatching ASAP
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -0800215 delete m_dispatcher; // stop dispatcher ASAP, but after watcher (to prevent triggering callbacks on deleted object)
Zhenkai Zhu8da33652013-03-04 10:52:03 -0800216 if (m_httpServer != 0)
217 {
218 m_httpServer->handle_stop();
219 m_httpServerThread.join();
220 delete m_httpServer;
221 }
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800222
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800223 // cleanup
224 delete m_trayIcon;
225 delete m_trayIconMenu;
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800226#ifdef ADHOC_SUPPORTED
227 delete m_wifiAction;
228#endif
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800229#ifdef SPARKLE_SUPPORTED
230 delete m_autoUpdate;
Zhenkai Zhubb170d42013-02-25 13:48:59 -0800231 delete m_checkForUpdates;
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800232#endif
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800233 delete m_openFolder;
234 delete m_viewSettings;
235 delete m_changeFolder;
236 delete m_quitProgram;
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800237
238 delete labelUsername;
239 delete labelSharedFolder;
240 delete editUsername;
241 delete editSharedFolder;
242 delete button;
243 delete label;
244 delete mainLayout;
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800245}
246
247void ChronoShareGui::openMessageBox(QString title, QString text)
248{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800249 QMessageBox messageBox(this);
250 messageBox.setWindowTitle(title);
251 messageBox.setText(text);
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800252
Zhenkai Zhud9429222013-02-25 22:34:09 -0800253 messageBox.setIconPixmap(QPixmap(ICON_PICTURE_QSTRING));
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800254
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800255 messageBox.exec();
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800256}
257
258void ChronoShareGui::openMessageBox(QString title, QString text, QString infotext)
259{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800260 QMessageBox messageBox(this);
261 messageBox.setWindowTitle(title);
262 messageBox.setText(text);
263 messageBox.setInformativeText(infotext);
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800264
Zhenkai Zhud9429222013-02-25 22:34:09 -0800265 messageBox.setIconPixmap(QPixmap(ICON_PICTURE_QSTRING));
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800266
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800267 messageBox.exec();
Jared Lindblom06405c42013-01-17 20:48:39 -0800268}
269
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800270void ChronoShareGui::createActionsAndMenu()
Jared Lindblom06405c42013-01-17 20:48:39 -0800271{
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800272 _LOG_DEBUG ("Create actions");
273
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800274 // create the "open folder" action
275 m_openFolder = new QAction(tr("&Open Folder"), this);
276 connect(m_openFolder, SIGNAL(triggered()), this, SLOT(openSharedFolder()));
Jared Lindblom06405c42013-01-17 20:48:39 -0800277
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800278 m_openWeb = new QAction(tr("Open in &Browser"), this);
279 connect(m_openWeb, SIGNAL(triggered()), this, SLOT(openInWebBrowser()));
280
281 m_recentFilesMenu = new QMenu(tr("Recently Changed Files"), this);
282 for (int i = 0; i < 5; i++)
283 {
284 m_fileActions[i] = new QAction(this);
285 m_fileActions[i]->setVisible(false);
286 connect(m_fileActions[i], SIGNAL(triggered()), this, SLOT(openFile()));
287 m_recentFilesMenu->addAction(m_fileActions[i]);
288 }
289 connect(m_recentFilesMenu, SIGNAL(aboutToShow()), this, SLOT(updateRecentFilesMenu()));
290
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800291 // create the "view settings" action
292 m_viewSettings = new QAction(tr("&View Settings"), this);
293 connect(m_viewSettings, SIGNAL(triggered()), this, SLOT(viewSettings()));
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800294
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800295 // create the "change folder" action
296 m_changeFolder = new QAction(tr("&Change Folder"), this);
297 connect(m_changeFolder, SIGNAL(triggered()), this, SLOT(openFileDialog()));
Jared Lindblomb4032e22013-01-17 23:50:51 -0800298
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800299#ifdef ADHOC_SUPPORTED
300 // create "AdHoc Wifi" action
301 m_wifiAction = new QAction (tr("Enable AdHoc &WiFI"), m_trayIconMenu);
302 m_wifiAction->setChecked (false);
303 m_wifiAction->setCheckable (true);
304 connect (m_wifiAction, SIGNAL (toggled(bool)), this, SLOT(onAdHocChange(bool)));
305#endif
306
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800307#ifdef SPARKLE_SUPPORTED
Zhenkai Zhubb170d42013-02-25 13:48:59 -0800308 m_checkForUpdates = new QAction (tr("Check For Updates"), this);
309 connect (m_checkForUpdates, SIGNAL(triggered()), this, SLOT(onCheckForUpdates()));
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800310#endif
311
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800312 // create the "quit program" action
313 m_quitProgram = new QAction(tr("&Quit"), this);
314 connect(m_quitProgram, SIGNAL(triggered()), qApp, SLOT(quit()));
Jared Lindblom06405c42013-01-17 20:48:39 -0800315}
316
317void ChronoShareGui::createTrayIcon()
318{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800319 // create a new icon menu
320 m_trayIconMenu = new QMenu(this);
Jared Lindblom06405c42013-01-17 20:48:39 -0800321
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800322 // add actions to the menu
323 m_trayIconMenu->addAction(m_openFolder);
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800324 m_trayIconMenu->addAction(m_openWeb);
325 m_trayIconMenu->addMenu(m_recentFilesMenu);
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800326 m_trayIconMenu->addSeparator();
327 m_trayIconMenu->addAction(m_viewSettings);
328 m_trayIconMenu->addAction(m_changeFolder);
Alexander Afanasyeve8496a32013-03-03 16:10:43 -0800329
330#ifdef SPARKLE_SUPPORTED
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800331 m_trayIconMenu->addSeparator();
Zhenkai Zhu3857d712013-02-27 22:51:25 -0800332 m_trayIconMenu->addAction(m_checkForUpdates);
Alexander Afanasyeve8496a32013-03-03 16:10:43 -0800333#endif
334
335#ifdef ADHOC_SUPPORTED
Zhenkai Zhu3857d712013-02-27 22:51:25 -0800336 m_trayIconMenu->addSeparator();
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800337 m_trayIconMenu->addAction(m_wifiAction);
Alexander Afanasyeve8496a32013-03-03 16:10:43 -0800338#endif
339
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800340 m_trayIconMenu->addSeparator();
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800341 m_trayIconMenu->addAction(m_quitProgram);
Jared Lindblom06405c42013-01-17 20:48:39 -0800342
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800343 // create new tray icon
344 m_trayIcon = new QSystemTrayIcon(this);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800345
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800346 // associate the menu with the tray icon
347 m_trayIcon->setContextMenu(m_trayIconMenu);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800348
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800349 // handle left click of icon
350 connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconClicked(QSystemTrayIcon::ActivationReason)));
Jared Lindblom06405c42013-01-17 20:48:39 -0800351}
352
Alexander Afanasyev85a4ba02013-02-24 16:30:17 -0800353void
354ChronoShareGui::onAdHocChange (bool state)
355{
356#ifdef ADHOC_SUPPORTED
357 if (m_wifiAction->isChecked ())
358 {
359 QMessageBox msgBox;
360 msgBox.setText ("WARNING: your WiFi will be disconnected");
361 msgBox.setIcon (QMessageBox::Warning);
362 msgBox.setInformativeText("AdHoc WiFi will disconnect your current WiFi.\n Are you sure that you are OK with that?");
363 msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
364 msgBox.setDefaultButton(QMessageBox::Cancel);
365 int ret = msgBox.exec();
366
367 if (ret == QMessageBox::Cancel)
368 {
369 m_wifiAction->setChecked (false);
370 }
371 else
372 {
373
374 m_wifiAction->setText (tr("Disable AdHoc WiFI"));
375
376 // create adhoc
377 m_executor.execute (Adhoc::CreateAdhoc);
378 }
379 }
380 else
381 {
382 m_wifiAction->setText (tr("Enable AdHoc WiFI"));
383
384 // disable adhoc
385 m_executor.execute (Adhoc::DestroyAdhoc);
386
387 // a trick in DestroyAdhoc ensures that WiFi will be reconnected to a default WiFi
388 }
389#endif
390}
391
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800392void
393ChronoShareGui::onCheckForUpdates()
394{
Zhenkai Zhu249fbc72013-02-27 21:50:25 -0800395#ifdef SPARKLE_SUPPORTED
Zhenkai Zhu3857d712013-02-27 22:51:25 -0800396 cout << "+++++++++++ trying to update +++++++ " << endl;
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800397 m_autoUpdate->checkForUpdates();
Zhenkai Zhu3857d712013-02-27 22:51:25 -0800398 cout << "+++++++++++ end trying to update +++++++ " << endl;
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800399#endif
Zhenkai Zhu249fbc72013-02-27 21:50:25 -0800400}
Zhenkai Zhuaca6cb52013-02-24 23:34:03 -0800401
Jared Lindblom06405c42013-01-17 20:48:39 -0800402void ChronoShareGui::setIcon()
403{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800404 // set the icon image
Zhenkai Zhud9429222013-02-25 22:34:09 -0800405 m_trayIcon->setIcon(QIcon(ICON_PICTURE_QSTRING));
Jared Lindblom06405c42013-01-17 20:48:39 -0800406}
407
408void ChronoShareGui::openSharedFolder()
409{
Zhenkai Zhu872cc592013-03-04 14:20:46 -0800410 filesystem::path realPathToFolder (m_dirPath.toStdString ());
411 realPathToFolder /= m_sharedFolderName.toStdString ();
412 QString path = QDir::toNativeSeparators(realPathToFolder.string().c_str());
Zhenkai Zhuce04cb42013-02-25 15:29:31 -0800413 QDesktopServices::openUrl(QUrl("file:///" + path));
Jared Lindblom06405c42013-01-17 20:48:39 -0800414}
Jared Lindblomb4032e22013-01-17 23:50:51 -0800415
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800416void ChronoShareGui::openInWebBrowser()
417{
Alexander Afanasyevf63a5142013-02-28 02:21:42 -0800418 QUrl url ("http://localhost:9001/");
Alexander Afanasyevc24db642013-03-09 16:41:02 -0800419 url.setFragment ("folderHistory&"
Alexander Afanasyevf63a5142013-02-28 02:21:42 -0800420 "user=" + QUrl::toPercentEncoding (m_username) + "&"
421 "folder=" + QUrl::toPercentEncoding (m_sharedFolderName));
422
423 // i give up. there is double encoding and I have no idea how to fight it...
424 QDesktopServices::openUrl (url);
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800425}
426
427void ChronoShareGui::openFile()
428{
429 // figure out who sent the signal
430 QAction *pAction = qobject_cast<QAction*>(sender());
431 if (pAction->isEnabled())
432 {
433 // we stored full path of the file in this toolTip field
434#ifdef Q_WS_MAC
435 // we do some hack so we could show the file in Finder highlighted
436 QStringList args;
437 args << "-e";
438 args << "tell application \"Finder\"";
439 args << "-e";
440 args << "activate";
441 args << "-e";
442 args << "select POSIX file \"" + pAction->toolTip() + "/" + pAction->text() + "\"";
443 args << "-e";
444 args << "end tell";
445 QProcess::startDetached("osascript", args);
446#else
447 // too bad qt couldn't do highlighting for Linux (or Mac)
448 QDesktopServices::openUrl(QUrl("file:///" + pAction->toolTip()));
449#endif
450 }
451}
452
453void ChronoShareGui::updateRecentFilesMenu()
454{
455 for (int i = 0; i < 5; i++)
456 {
457 m_fileActions[i]->setVisible(false);
458 }
459 m_dispatcher->LookupRecentFileActions(boost::bind(&ChronoShareGui::checkFileAction, this, _1, _2, _3), 5);
460}
461
462void ChronoShareGui::checkFileAction (const std::string &filename, int action, int index)
463{
Zhenkai Zhu872cc592013-03-04 14:20:46 -0800464 filesystem::path realPathToFolder (m_dirPath.toStdString ());
465 realPathToFolder /= m_sharedFolderName.toStdString ();
466 realPathToFolder /= filename;
467 QString fullPath = realPathToFolder.string().c_str();
Zhenkai Zhu25e13582013-02-27 15:33:01 -0800468 QFileInfo fileInfo(fullPath);
469 if (fileInfo.exists())
470 {
471 // This is a hack, we just use some field to store the path
472 m_fileActions[index]->setToolTip(fileInfo.absolutePath());
473 m_fileActions[index]->setEnabled(true);
474 }
475 else
476 {
477 // after half an hour frustrating test and search around,
478 // I think it's the problem of Qt.
479 // According to the Qt doc, the action cannot be clicked
480 // and the area would be grey, but it didn't happen
481 // User can still trigger the action, and not greyed
482 // added check in SLOT to see if the action is "enalbed"
483 // as a remedy
484 // Give up at least for now
485 m_fileActions[index]->setEnabled(false);
486 // UPDATE, file not fetched yet
487 if (action == 0)
488 {
489 QFont font;
490 // supposed by change the font, didn't happen
491 font.setWeight(QFont::Light);
492 m_fileActions[index]->setFont(font);
493 m_fileActions[index]->setToolTip(tr("Fetching..."));
494 }
495 // DELETE
496 else
497 {
498 QFont font;
499 // supposed by change the font, didn't happen
500 font.setStrikeOut(true);
501 m_fileActions[index]->setFont(font);
502 m_fileActions[index]->setToolTip(tr("Deleted..."));
503 }
504 }
505 m_fileActions[index]->setText(fileInfo.fileName());
506 m_fileActions[index]->setVisible(true);
507}
508
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800509void ChronoShareGui::changeSettings()
510{
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800511 QString oldUsername = m_username;
512 QString oldSharedFolderName = m_sharedFolderName;
513
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800514 if(!editUsername->text().isEmpty())
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -0800515 m_username = editUsername->text().trimmed();
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800516 else
517 editUsername->setText(m_username);
518
519 if(!editSharedFolder->text().isEmpty())
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -0800520 m_sharedFolderName = editSharedFolder->text().trimmed();
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800521 else
522 editSharedFolder->setText(m_sharedFolderName);
523
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800524 if (m_username.isNull () || m_username=="" ||
525 m_sharedFolderName.isNull () || m_sharedFolderName=="")
526 {
527 openMessageBox ("Error",
528 "Username and shared folder name cannot be empty");
529 }
530 else
531 {
532 saveSettings();
533 this->hide();
Zhenkai Zhud5756312013-01-31 13:49:45 -0800534
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800535 if (m_username != oldUsername ||
536 oldSharedFolderName != m_sharedFolderName)
537 {
538 startBackend (true); // restart dispatcher/fswatcher
539 }
540 }
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800541}
542
Jared Lindblomb4032e22013-01-17 23:50:51 -0800543void ChronoShareGui::openFileDialog()
544{
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800545 while (true)
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800546 {
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800547 // prompt user for new directory
548 QString tempPath = QFileDialog::getExistingDirectory(this, tr("Choose ChronoShare folder"),
549 m_dirPath, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
550 if (tempPath.isNull ())
551 {
552 if (m_dirPath.isNull ())
553 {
554 openMessageBox ("Notice", "ChronoShare will use [" + QDir::homePath () + "/ChronoShare]. \n\nYou can change it later selecting \"Change Folder\" menu.");
555
556 m_dirPath = QDir::homePath () + "/ChronoShare";
557 editSharedFolderPath->setText (m_dirPath);
558 break;
559 }
560 else
561 {
562 // user just cancelled, no need to do anything else
563 return;
564 }
565 }
566
567 QFileInfo qFileInfo (tempPath);
568
569 if (!qFileInfo.isDir())
570 {
571 openMessageBox ("Error", "Please select an existing folder or create a new one.");
572 continue;
573 }
574
575 if (m_dirPath == tempPath)
576 {
577 // user selected the same directory, no need to do anything
578 return;
579 }
580
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800581 m_dirPath = tempPath;
582 editSharedFolderPath->setText(m_dirPath);
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800583 break;
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800584 }
Jared Lindblomb4032e22013-01-17 23:50:51 -0800585
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800586 _LOG_DEBUG ("Selected path: " << m_dirPath.toStdString ());
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800587 // save settings
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800588 saveSettings ();
589
590 startBackend (true); // restart dispatcher/fswatcher
Jared Lindblomb4032e22013-01-17 23:50:51 -0800591}
592
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800593void ChronoShareGui::trayIconClicked (QSystemTrayIcon::ActivationReason reason)
Jared Lindblomb4032e22013-01-17 23:50:51 -0800594{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800595 // if double clicked, open shared folder
596 if(reason == QSystemTrayIcon::DoubleClick)
Jared Lindblomb4032e22013-01-17 23:50:51 -0800597 {
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800598 openSharedFolder();
Jared Lindblomb4032e22013-01-17 23:50:51 -0800599 }
600}
601
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800602void ChronoShareGui::viewSettings()
Jared Lindblomb4032e22013-01-17 23:50:51 -0800603{
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800604 //simple for now
605 this->show();
Zhenkai Zhud5756312013-01-31 13:49:45 -0800606 this->raise();
607 this->activateWindow();
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800608}
609
610bool ChronoShareGui::loadSettings()
611{
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800612 bool successful = true;
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800613
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800614 // Load Settings
615 // QSettings settings(m_settingsFilePath, QSettings::NativeFormat);
616 QSettings settings (QSettings::NativeFormat, QSettings::UserScope, "irl.cs.ucla.edu", "ChronoShare");
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800617
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800618 // _LOG_DEBUG (lexical_cast<string> (settings.allKeys()));
619
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800620 if(settings.contains("username"))
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800621 {
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800622 m_username = settings.value("username", "admin").toString();
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800623 }
624 else
625 {
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800626 successful = false;
627 }
628
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800629 editUsername->setText(m_username);
630
631 if(settings.contains("sharedfoldername"))
632 {
633 m_sharedFolderName = settings.value("sharedfoldername", "shared").toString();
634 }
635 else
636 {
637 successful = false;
638 }
639
640 editSharedFolder->setText(m_sharedFolderName);
641
642 if(settings.contains("dirPath"))
643 {
644 m_dirPath = settings.value("dirPath", QDir::homePath()).toString();
645 }
646 else
647 {
648 successful = false;
649 }
650
651 editSharedFolderPath->setText(m_dirPath);
652
653 _LOG_DEBUG ("Found configured path: " << (successful ? m_dirPath.toStdString () : std::string("no")));
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800654
655 return successful;
Jared Lindblomb4032e22013-01-17 23:50:51 -0800656}
657
658void ChronoShareGui::saveSettings()
659{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800660 // Save Settings
661 // QSettings settings(m_settingsFilePath, QSettings::NativeFormat);
662 QSettings settings (QSettings::NativeFormat, QSettings::UserScope, "irl.cs.ucla.edu", "ChronoShare");
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800663
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800664 settings.setValue("dirPath", m_dirPath);
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800665 settings.setValue("username", m_username);
666 settings.setValue("sharedfoldername", m_sharedFolderName);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800667}
668
669void ChronoShareGui::closeEvent(QCloseEvent* event)
670{
Alexander Afanasyevd437ffc2013-03-04 12:29:23 -0800671 _LOG_DEBUG ("Close Event");
672
673 if (m_username.isNull () || m_username == "" ||
674 m_sharedFolderName.isNull () || m_sharedFolderName == "")
675 {
676 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");
677 }
678
679 this->hide();
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800680 event->ignore(); // don't let the event propagate to the base class
Jared Lindblomb4032e22013-01-17 23:50:51 -0800681}
Jared Lindblomdc845f02013-01-18 17:29:40 -0800682
683#if WAF
684#include "chronosharegui.moc"
685#include "chronosharegui.cpp.moc"
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800686#endif