blob: 5889ede913f37b0dbe25ee864424565f6eb1d5a8 [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>
19 */
20
21#include "chronosharegui.h"
Alexander Afanasyev83a53002013-01-24 11:12:01 -080022#include "logging.h"
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -080023#include "ccnx-wrapper.h"
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080024#include <QValidator>
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -080025
26#include <boost/make_shared.hpp>
27
28using namespace boost;
29using namespace Ccnx;
Jared Lindblom06405c42013-01-17 20:48:39 -080030
Alexander Afanasyev83a53002013-01-24 11:12:01 -080031INIT_LOGGER ("Gui");
32
33ChronoShareGui::ChronoShareGui(QWidget *parent)
Jared Lindblomc8ffd592013-01-25 00:00:30 -080034 : QDialog(parent)
Zhenkai Zhud5756312013-01-31 13:49:45 -080035 , m_watcher(0)
36 , m_dispatcher(0)
Jared Lindblom06405c42013-01-17 20:48:39 -080037{
Jared Lindblomc8ffd592013-01-25 00:00:30 -080038
39 setWindowTitle("Preferences");
40
41 labelUsername = new QLabel("Username");
42 labelSharedFolder = new QLabel("Shared Folder Name");
43 labelSharedFolderPath = new QLabel("Shared Folder Path");
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080044
Zhenkai Zhud5756312013-01-31 13:49:45 -080045 QRegExp regex("(/[^/]+)+$");
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080046 QValidator *prefixValidator = new QRegExpValidator(regex, this);
47
Jared Lindblomc8ffd592013-01-25 00:00:30 -080048 editUsername = new QLineEdit();
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080049 editUsername->setValidator(prefixValidator);
50
51 QRegExp noPureWhiteSpace("^\\S+.*$");
52 QValidator *wsValidator = new QRegExpValidator(noPureWhiteSpace, this);
Jared Lindblomc8ffd592013-01-25 00:00:30 -080053 editSharedFolder = new QLineEdit();
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080054 editSharedFolder->setValidator(wsValidator);
55
Jared Lindblomc8ffd592013-01-25 00:00:30 -080056 editSharedFolderPath = new QLineEdit();
57 editSharedFolderPath->setReadOnly(true);
58 QPalette pal = editSharedFolderPath->palette();
59 pal.setColor(QPalette::Active, QPalette::Base, pal.color(QPalette::Disabled, QPalette::Base));
60 editSharedFolderPath->setPalette(pal);
61 button = new QPushButton("Submit");
62 label = new QLabel();
63
64 connect(button, SIGNAL(clicked()), this, SLOT(changeSettings()));
65
66 mainLayout = new QVBoxLayout; //vertically
67 mainLayout->addWidget(labelUsername);
68 mainLayout->addWidget(editUsername);
69 mainLayout->addWidget(labelSharedFolder);
70 mainLayout->addWidget(editSharedFolder);
71 mainLayout->addWidget(labelSharedFolderPath);
72 mainLayout->addWidget(editSharedFolderPath);
73 mainLayout->addWidget(button);
74 mainLayout->addWidget(label);
75 setLayout(mainLayout);
76
Alexander Afanasyev83a53002013-01-24 11:12:01 -080077 // create actions that result from clicking a menu option
78 createActions();
Jared Lindblomb4032e22013-01-17 23:50:51 -080079
Alexander Afanasyev83a53002013-01-24 11:12:01 -080080 // create tray icon
81 createTrayIcon();
Jared Lindblomb4032e22013-01-17 23:50:51 -080082
Alexander Afanasyev83a53002013-01-24 11:12:01 -080083 // set icon image
84 setIcon();
Jared Lindblom06405c42013-01-17 20:48:39 -080085
Alexander Afanasyev83a53002013-01-24 11:12:01 -080086 // show tray icon
87 m_trayIcon->show();
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080088
89 // Dispatcher(const boost::filesystem::path &path, const std::string &localUserName, const Ccnx::Name &localPrefix,
90 // const std::string &sharedFolder, const boost::filesystem::path &rootDir,
91 // Ccnx::CcnxWrapperPtr ccnx, SchedulerPtr scheduler, int poolSize = 2);
92
Zhenkai Zhud5756312013-01-31 13:49:45 -080093 // load settings
94 if(!loadSettings())
95 {
96 // prompt user to choose folder
97 openMessageBox("First Time Setup", "Please enter a username, shared folder name and choose the shared folder path on your local filesystem.");
98 viewSettings();
99 openFileDialog();
100 viewSettings();
101 }
102 else
103 {
104 startBackend();
105 }
106}
107
108void
109ChronoShareGui::startBackend()
110{
111 if (m_watcher != 0 && m_dispatcher != 0)
112 {
113 return;
114 }
115
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -0800116 m_dispatcher = new Dispatcher (m_username.toStdString (), m_sharedFolderName.toStdString (),
117 m_dirPath.toStdString (), make_shared<CcnxWrapper> ());
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800118
119 // Alex: this **must** be here, otherwise m_dirPath will be uninitialized
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -0800120 m_watcher = new FsWatcher (m_dirPath,
121 bind (&Dispatcher::Did_LocalFile_AddOrModify, m_dispatcher, _1),
Alexander Afanasyev0a30a0c2013-01-29 17:25:42 -0800122 bind (&Dispatcher::Did_LocalFile_Delete, m_dispatcher, _1),
123 m_dispatcher->GetFileState ());
Jared Lindblom06405c42013-01-17 20:48:39 -0800124}
125
126ChronoShareGui::~ChronoShareGui()
127{
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800128 delete m_watcher; // stop filewatching ASAP
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -0800129 delete m_dispatcher; // stop dispatcher ASAP, but after watcher (to prevent triggering callbacks on deleted object)
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800130
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800131 // cleanup
132 delete m_trayIcon;
133 delete m_trayIconMenu;
134 delete m_openFolder;
135 delete m_viewSettings;
136 delete m_changeFolder;
137 delete m_quitProgram;
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800138
139 delete labelUsername;
140 delete labelSharedFolder;
141 delete editUsername;
142 delete editSharedFolder;
143 delete button;
144 delete label;
145 delete mainLayout;
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800146}
147
148void ChronoShareGui::openMessageBox(QString title, QString text)
149{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800150 QMessageBox messageBox(this);
151 messageBox.setWindowTitle(title);
152 messageBox.setText(text);
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800153
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800154 messageBox.setIconPixmap(QPixmap(":/images/friends-group-icon.png"));
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800155
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800156 messageBox.exec();
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800157}
158
159void ChronoShareGui::openMessageBox(QString title, QString text, QString infotext)
160{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800161 QMessageBox messageBox(this);
162 messageBox.setWindowTitle(title);
163 messageBox.setText(text);
164 messageBox.setInformativeText(infotext);
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800165
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800166 messageBox.setIconPixmap(QPixmap(":/images/friends-group-icon.png"));
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800167
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800168 messageBox.exec();
Jared Lindblom06405c42013-01-17 20:48:39 -0800169}
170
171void ChronoShareGui::createActions()
172{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800173 // create the "open folder" action
174 m_openFolder = new QAction(tr("&Open Folder"), this);
175 connect(m_openFolder, SIGNAL(triggered()), this, SLOT(openSharedFolder()));
Jared Lindblom06405c42013-01-17 20:48:39 -0800176
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800177 // create the "view settings" action
178 m_viewSettings = new QAction(tr("&View Settings"), this);
179 connect(m_viewSettings, SIGNAL(triggered()), this, SLOT(viewSettings()));
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800180
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800181 // create the "change folder" action
182 m_changeFolder = new QAction(tr("&Change Folder"), this);
183 connect(m_changeFolder, SIGNAL(triggered()), this, SLOT(openFileDialog()));
Jared Lindblomb4032e22013-01-17 23:50:51 -0800184
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800185 // create the "quit program" action
186 m_quitProgram = new QAction(tr("&Quit"), this);
187 connect(m_quitProgram, SIGNAL(triggered()), qApp, SLOT(quit()));
Jared Lindblom06405c42013-01-17 20:48:39 -0800188}
189
190void ChronoShareGui::createTrayIcon()
191{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800192 // create a new icon menu
193 m_trayIconMenu = new QMenu(this);
Jared Lindblom06405c42013-01-17 20:48:39 -0800194
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800195 // add actions to the menu
196 m_trayIconMenu->addAction(m_openFolder);
197 m_trayIconMenu->addSeparator();
198 m_trayIconMenu->addAction(m_viewSettings);
199 m_trayIconMenu->addAction(m_changeFolder);
200 m_trayIconMenu->addSeparator();
201 m_trayIconMenu->addAction(m_quitProgram);
Jared Lindblom06405c42013-01-17 20:48:39 -0800202
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800203 // create new tray icon
204 m_trayIcon = new QSystemTrayIcon(this);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800205
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800206 // associate the menu with the tray icon
207 m_trayIcon->setContextMenu(m_trayIconMenu);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800208
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800209 // handle left click of icon
210 connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconClicked(QSystemTrayIcon::ActivationReason)));
Jared Lindblom06405c42013-01-17 20:48:39 -0800211}
212
213void ChronoShareGui::setIcon()
214{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800215 // set the icon image
216 m_trayIcon->setIcon(QIcon(":/images/friends-group-icon.png"));
Jared Lindblom06405c42013-01-17 20:48:39 -0800217}
218
219void ChronoShareGui::openSharedFolder()
220{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800221 // Alex: isn't there an OS-independent way in QT for this?
Jared Lindblomb4032e22013-01-17 23:50:51 -0800222
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800223 // tell Finder to open the shared folder
224 QStringList scriptArgs;
225 scriptArgs << QLatin1String("-e")
226 << QString::fromLatin1("tell application \"Finder\" to reveal POSIX file \"%1\"")
227 .arg(m_dirPath);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800228
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800229 // execute the commands to make it happen
230 QProcess::execute(QLatin1String("/usr/bin/osascript"), scriptArgs);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800231
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800232 // clear command arguments
233 scriptArgs.clear();
Jared Lindblomb4032e22013-01-17 23:50:51 -0800234
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800235 // tell Finder to appear
236 scriptArgs << QLatin1String("-e")
237 << QLatin1String("tell application \"Finder\" to activate");
238
239 // execute the commands to make it happen
240 QProcess::execute("/usr/bin/osascript", scriptArgs);
Jared Lindblom06405c42013-01-17 20:48:39 -0800241}
Jared Lindblomb4032e22013-01-17 23:50:51 -0800242
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800243void ChronoShareGui::changeSettings()
244{
245 if(!editUsername->text().isEmpty())
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -0800246 m_username = editUsername->text().trimmed();
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800247 else
248 editUsername->setText(m_username);
249
250 if(!editSharedFolder->text().isEmpty())
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -0800251 m_sharedFolderName = editSharedFolder->text().trimmed();
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800252 else
253 editSharedFolder->setText(m_sharedFolderName);
254
255 saveSettings();
256 this->hide();
Zhenkai Zhud5756312013-01-31 13:49:45 -0800257
258 startBackend();
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800259}
260
Jared Lindblomb4032e22013-01-17 23:50:51 -0800261void ChronoShareGui::openFileDialog()
262{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800263 // prompt user for new directory
264 QString tempPath = QFileDialog::getExistingDirectory(this, tr("Choose a new folder"),
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800265 m_dirPath, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
266 QFileInfo qFileInfo (tempPath);
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800267
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800268 if(qFileInfo.isDir())
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800269 {
270 m_dirPath = tempPath;
271 editSharedFolderPath->setText(m_dirPath);
272 }
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800273 else
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800274 {
275 openMessageBox ("Error", "Not a valid folder, Ignoring.");
276 }
Jared Lindblomb4032e22013-01-17 23:50:51 -0800277
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800278 _LOG_DEBUG ("Selected path: " << m_dirPath.toStdString ());
Jared Lindblomb4032e22013-01-17 23:50:51 -0800279
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800280 // save settings
281 saveSettings();
Jared Lindblomb4032e22013-01-17 23:50:51 -0800282}
283
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800284void ChronoShareGui::trayIconClicked (QSystemTrayIcon::ActivationReason reason)
Jared Lindblomb4032e22013-01-17 23:50:51 -0800285{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800286 // if double clicked, open shared folder
287 if(reason == QSystemTrayIcon::DoubleClick)
Jared Lindblomb4032e22013-01-17 23:50:51 -0800288 {
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800289 openSharedFolder();
Jared Lindblomb4032e22013-01-17 23:50:51 -0800290 }
291}
292
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800293void ChronoShareGui::viewSettings()
Jared Lindblomb4032e22013-01-17 23:50:51 -0800294{
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800295 //simple for now
296 this->show();
Zhenkai Zhud5756312013-01-31 13:49:45 -0800297 this->raise();
298 this->activateWindow();
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800299}
300
301bool ChronoShareGui::loadSettings()
302{
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800303 bool successful = true;
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800304
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800305 // Load Settings
306 // QSettings settings(m_settingsFilePath, QSettings::NativeFormat);
307 QSettings settings (QSettings::NativeFormat, QSettings::UserScope, "irl.cs.ucla.edu", "ChronoShare");
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800308
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800309 // _LOG_DEBUG (lexical_cast<string> (settings.allKeys()));
310
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800311 if(settings.contains("username"))
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800312 {
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800313 m_username = settings.value("username", "admin").toString();
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800314 }
315 else
316 {
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800317 successful = false;
318 }
319
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800320 editUsername->setText(m_username);
321
322 if(settings.contains("sharedfoldername"))
323 {
324 m_sharedFolderName = settings.value("sharedfoldername", "shared").toString();
325 }
326 else
327 {
328 successful = false;
329 }
330
331 editSharedFolder->setText(m_sharedFolderName);
332
333 if(settings.contains("dirPath"))
334 {
335 m_dirPath = settings.value("dirPath", QDir::homePath()).toString();
336 }
337 else
338 {
339 successful = false;
340 }
341
342 editSharedFolderPath->setText(m_dirPath);
343
344 _LOG_DEBUG ("Found configured path: " << (successful ? m_dirPath.toStdString () : std::string("no")));
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800345
346 return successful;
Jared Lindblomb4032e22013-01-17 23:50:51 -0800347}
348
349void ChronoShareGui::saveSettings()
350{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800351 // Save Settings
352 // QSettings settings(m_settingsFilePath, QSettings::NativeFormat);
353 QSettings settings (QSettings::NativeFormat, QSettings::UserScope, "irl.cs.ucla.edu", "ChronoShare");
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800354
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800355 settings.setValue("dirPath", m_dirPath);
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800356 settings.setValue("username", m_username);
357 settings.setValue("sharedfoldername", m_sharedFolderName);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800358}
359
360void ChronoShareGui::closeEvent(QCloseEvent* event)
361{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800362 _LOG_DEBUG ("Close Event")
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800363 this->hide();
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800364 event->ignore(); // don't let the event propagate to the base class
Jared Lindblomb4032e22013-01-17 23:50:51 -0800365}
Jared Lindblomdc845f02013-01-18 17:29:40 -0800366
367#if WAF
368#include "chronosharegui.moc"
369#include "chronosharegui.cpp.moc"
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800370#endif