blob: fcfb6e259924677772b59e52ba39a0f4b1fef064 [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)
Jared Lindblom06405c42013-01-17 20:48:39 -080035{
Jared Lindblomc8ffd592013-01-25 00:00:30 -080036
37 setWindowTitle("Preferences");
38
39 labelUsername = new QLabel("Username");
40 labelSharedFolder = new QLabel("Shared Folder Name");
41 labelSharedFolderPath = new QLabel("Shared Folder Path");
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080042
43 QRegExp regex("(^/[^/]+)+$");
44 QValidator *prefixValidator = new QRegExpValidator(regex, this);
45
Jared Lindblomc8ffd592013-01-25 00:00:30 -080046 editUsername = new QLineEdit();
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080047 editUsername->setValidator(prefixValidator);
48
49 QRegExp noPureWhiteSpace("^\\S+.*$");
50 QValidator *wsValidator = new QRegExpValidator(noPureWhiteSpace, this);
Jared Lindblomc8ffd592013-01-25 00:00:30 -080051 editSharedFolder = new QLineEdit();
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -080052 editSharedFolder->setValidator(wsValidator);
53
Jared Lindblomc8ffd592013-01-25 00:00:30 -080054 editSharedFolderPath = new QLineEdit();
55 editSharedFolderPath->setReadOnly(true);
56 QPalette pal = editSharedFolderPath->palette();
57 pal.setColor(QPalette::Active, QPalette::Base, pal.color(QPalette::Disabled, QPalette::Base));
58 editSharedFolderPath->setPalette(pal);
59 button = new QPushButton("Submit");
60 label = new QLabel();
61
62 connect(button, SIGNAL(clicked()), this, SLOT(changeSettings()));
63
64 mainLayout = new QVBoxLayout; //vertically
65 mainLayout->addWidget(labelUsername);
66 mainLayout->addWidget(editUsername);
67 mainLayout->addWidget(labelSharedFolder);
68 mainLayout->addWidget(editSharedFolder);
69 mainLayout->addWidget(labelSharedFolderPath);
70 mainLayout->addWidget(editSharedFolderPath);
71 mainLayout->addWidget(button);
72 mainLayout->addWidget(label);
73 setLayout(mainLayout);
74
Alexander Afanasyev83a53002013-01-24 11:12:01 -080075 // load settings
76 if(!loadSettings())
Jared Lindblom5d7e51e2013-01-18 00:59:34 -080077 {
Alexander Afanasyev83a53002013-01-24 11:12:01 -080078 // prompt user to choose folder
Jared Lindblomc8ffd592013-01-25 00:00:30 -080079 openMessageBox("First Time Setup", "Please enter a username, shared folder name and choose the shared folder path on your local filesystem.");
80 viewSettings();
Alexander Afanasyev83a53002013-01-24 11:12:01 -080081 openFileDialog();
Jared Lindblomc8ffd592013-01-25 00:00:30 -080082 viewSettings();
Jared Lindblom5d7e51e2013-01-18 00:59:34 -080083 }
Jared Lindblomb4032e22013-01-17 23:50:51 -080084
Alexander Afanasyev83a53002013-01-24 11:12:01 -080085 // create actions that result from clicking a menu option
86 createActions();
Jared Lindblomb4032e22013-01-17 23:50:51 -080087
Alexander Afanasyev83a53002013-01-24 11:12:01 -080088 // create tray icon
89 createTrayIcon();
Jared Lindblomb4032e22013-01-17 23:50:51 -080090
Alexander Afanasyev83a53002013-01-24 11:12:01 -080091 // set icon image
92 setIcon();
Jared Lindblom06405c42013-01-17 20:48:39 -080093
Alexander Afanasyev83a53002013-01-24 11:12:01 -080094 // show tray icon
95 m_trayIcon->show();
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -080096
97 // Dispatcher(const boost::filesystem::path &path, const std::string &localUserName, const Ccnx::Name &localPrefix,
98 // const std::string &sharedFolder, const boost::filesystem::path &rootDir,
99 // Ccnx::CcnxWrapperPtr ccnx, SchedulerPtr scheduler, int poolSize = 2);
100
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -0800101 m_dispatcher = new Dispatcher (m_username.toStdString (), m_sharedFolderName.toStdString (),
102 m_dirPath.toStdString (), make_shared<CcnxWrapper> ());
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800103
104 // Alex: this **must** be here, otherwise m_dirPath will be uninitialized
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -0800105 m_watcher = new FsWatcher (m_dirPath,
106 bind (&Dispatcher::Did_LocalFile_AddOrModify, m_dispatcher, _1),
Alexander Afanasyev0a30a0c2013-01-29 17:25:42 -0800107 bind (&Dispatcher::Did_LocalFile_Delete, m_dispatcher, _1),
108 m_dispatcher->GetFileState ());
Jared Lindblom06405c42013-01-17 20:48:39 -0800109}
110
111ChronoShareGui::~ChronoShareGui()
112{
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800113 delete m_watcher; // stop filewatching ASAP
Alexander Afanasyev9ca444e2013-01-25 16:29:35 -0800114 delete m_dispatcher; // stop dispatcher ASAP, but after watcher (to prevent triggering callbacks on deleted object)
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800115
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800116 // cleanup
117 delete m_trayIcon;
118 delete m_trayIconMenu;
119 delete m_openFolder;
120 delete m_viewSettings;
121 delete m_changeFolder;
122 delete m_quitProgram;
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800123
124 delete labelUsername;
125 delete labelSharedFolder;
126 delete editUsername;
127 delete editSharedFolder;
128 delete button;
129 delete label;
130 delete mainLayout;
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800131}
132
133void ChronoShareGui::openMessageBox(QString title, QString text)
134{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800135 QMessageBox messageBox(this);
136 messageBox.setWindowTitle(title);
137 messageBox.setText(text);
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800138
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800139 messageBox.setIconPixmap(QPixmap(":/images/friends-group-icon.png"));
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800140
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800141 messageBox.exec();
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800142}
143
144void ChronoShareGui::openMessageBox(QString title, QString text, QString infotext)
145{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800146 QMessageBox messageBox(this);
147 messageBox.setWindowTitle(title);
148 messageBox.setText(text);
149 messageBox.setInformativeText(infotext);
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800150
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800151 messageBox.setIconPixmap(QPixmap(":/images/friends-group-icon.png"));
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800152
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800153 messageBox.exec();
Jared Lindblom06405c42013-01-17 20:48:39 -0800154}
155
156void ChronoShareGui::createActions()
157{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800158 // create the "open folder" action
159 m_openFolder = new QAction(tr("&Open Folder"), this);
160 connect(m_openFolder, SIGNAL(triggered()), this, SLOT(openSharedFolder()));
Jared Lindblom06405c42013-01-17 20:48:39 -0800161
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800162 // create the "view settings" action
163 m_viewSettings = new QAction(tr("&View Settings"), this);
164 connect(m_viewSettings, SIGNAL(triggered()), this, SLOT(viewSettings()));
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800165
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800166 // create the "change folder" action
167 m_changeFolder = new QAction(tr("&Change Folder"), this);
168 connect(m_changeFolder, SIGNAL(triggered()), this, SLOT(openFileDialog()));
Jared Lindblomb4032e22013-01-17 23:50:51 -0800169
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800170 // create the "quit program" action
171 m_quitProgram = new QAction(tr("&Quit"), this);
172 connect(m_quitProgram, SIGNAL(triggered()), qApp, SLOT(quit()));
Jared Lindblom06405c42013-01-17 20:48:39 -0800173}
174
175void ChronoShareGui::createTrayIcon()
176{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800177 // create a new icon menu
178 m_trayIconMenu = new QMenu(this);
Jared Lindblom06405c42013-01-17 20:48:39 -0800179
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800180 // add actions to the menu
181 m_trayIconMenu->addAction(m_openFolder);
182 m_trayIconMenu->addSeparator();
183 m_trayIconMenu->addAction(m_viewSettings);
184 m_trayIconMenu->addAction(m_changeFolder);
185 m_trayIconMenu->addSeparator();
186 m_trayIconMenu->addAction(m_quitProgram);
Jared Lindblom06405c42013-01-17 20:48:39 -0800187
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800188 // create new tray icon
189 m_trayIcon = new QSystemTrayIcon(this);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800190
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800191 // associate the menu with the tray icon
192 m_trayIcon->setContextMenu(m_trayIconMenu);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800193
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800194 // handle left click of icon
195 connect(m_trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconClicked(QSystemTrayIcon::ActivationReason)));
Jared Lindblom06405c42013-01-17 20:48:39 -0800196}
197
198void ChronoShareGui::setIcon()
199{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800200 // set the icon image
201 m_trayIcon->setIcon(QIcon(":/images/friends-group-icon.png"));
Jared Lindblom06405c42013-01-17 20:48:39 -0800202}
203
204void ChronoShareGui::openSharedFolder()
205{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800206 // Alex: isn't there an OS-independent way in QT for this?
Jared Lindblomb4032e22013-01-17 23:50:51 -0800207
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800208 // tell Finder to open the shared folder
209 QStringList scriptArgs;
210 scriptArgs << QLatin1String("-e")
211 << QString::fromLatin1("tell application \"Finder\" to reveal POSIX file \"%1\"")
212 .arg(m_dirPath);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800213
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800214 // execute the commands to make it happen
215 QProcess::execute(QLatin1String("/usr/bin/osascript"), scriptArgs);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800216
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800217 // clear command arguments
218 scriptArgs.clear();
Jared Lindblomb4032e22013-01-17 23:50:51 -0800219
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800220 // tell Finder to appear
221 scriptArgs << QLatin1String("-e")
222 << QLatin1String("tell application \"Finder\" to activate");
223
224 // execute the commands to make it happen
225 QProcess::execute("/usr/bin/osascript", scriptArgs);
Jared Lindblom06405c42013-01-17 20:48:39 -0800226}
Jared Lindblomb4032e22013-01-17 23:50:51 -0800227
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800228void ChronoShareGui::changeSettings()
229{
230 if(!editUsername->text().isEmpty())
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -0800231 m_username = editUsername->text().trimmed();
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800232 else
233 editUsername->setText(m_username);
234
235 if(!editSharedFolder->text().isEmpty())
Zhenkai Zhuf3ea97a2013-01-30 15:20:52 -0800236 m_sharedFolderName = editSharedFolder->text().trimmed();
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800237 else
238 editSharedFolder->setText(m_sharedFolderName);
239
240 saveSettings();
241 this->hide();
242}
243
Jared Lindblomb4032e22013-01-17 23:50:51 -0800244void ChronoShareGui::openFileDialog()
245{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800246 // prompt user for new directory
247 QString tempPath = QFileDialog::getExistingDirectory(this, tr("Choose a new folder"),
Alexander Afanasyev9e5a4702013-01-24 13:15:23 -0800248 m_dirPath, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
249 QFileInfo qFileInfo (tempPath);
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800250
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800251 if(qFileInfo.isDir())
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800252 {
253 m_dirPath = tempPath;
254 editSharedFolderPath->setText(m_dirPath);
255 }
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800256 else
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800257 {
258 openMessageBox ("Error", "Not a valid folder, Ignoring.");
259 }
Jared Lindblomb4032e22013-01-17 23:50:51 -0800260
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800261 _LOG_DEBUG ("Selected path: " << m_dirPath.toStdString ());
Jared Lindblomb4032e22013-01-17 23:50:51 -0800262
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800263 // save settings
264 saveSettings();
Jared Lindblomb4032e22013-01-17 23:50:51 -0800265}
266
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800267void ChronoShareGui::trayIconClicked (QSystemTrayIcon::ActivationReason reason)
Jared Lindblomb4032e22013-01-17 23:50:51 -0800268{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800269 // if double clicked, open shared folder
270 if(reason == QSystemTrayIcon::DoubleClick)
Jared Lindblomb4032e22013-01-17 23:50:51 -0800271 {
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800272 openSharedFolder();
Jared Lindblomb4032e22013-01-17 23:50:51 -0800273 }
274}
275
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800276void ChronoShareGui::viewSettings()
Jared Lindblomb4032e22013-01-17 23:50:51 -0800277{
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800278 //simple for now
279 this->show();
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800280}
281
282bool ChronoShareGui::loadSettings()
283{
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800284 bool successful = true;
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800285
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800286 // Load Settings
287 // QSettings settings(m_settingsFilePath, QSettings::NativeFormat);
288 QSettings settings (QSettings::NativeFormat, QSettings::UserScope, "irl.cs.ucla.edu", "ChronoShare");
Jared Lindblom5d7e51e2013-01-18 00:59:34 -0800289
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800290 // _LOG_DEBUG (lexical_cast<string> (settings.allKeys()));
291
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800292 if(settings.contains("username"))
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800293 {
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800294 m_username = settings.value("username", "admin").toString();
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800295 }
296 else
297 {
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800298 successful = false;
299 }
300
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800301 editUsername->setText(m_username);
302
303 if(settings.contains("sharedfoldername"))
304 {
305 m_sharedFolderName = settings.value("sharedfoldername", "shared").toString();
306 }
307 else
308 {
309 successful = false;
310 }
311
312 editSharedFolder->setText(m_sharedFolderName);
313
314 if(settings.contains("dirPath"))
315 {
316 m_dirPath = settings.value("dirPath", QDir::homePath()).toString();
317 }
318 else
319 {
320 successful = false;
321 }
322
323 editSharedFolderPath->setText(m_dirPath);
324
325 _LOG_DEBUG ("Found configured path: " << (successful ? m_dirPath.toStdString () : std::string("no")));
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800326
327 return successful;
Jared Lindblomb4032e22013-01-17 23:50:51 -0800328}
329
330void ChronoShareGui::saveSettings()
331{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800332 // Save Settings
333 // QSettings settings(m_settingsFilePath, QSettings::NativeFormat);
334 QSettings settings (QSettings::NativeFormat, QSettings::UserScope, "irl.cs.ucla.edu", "ChronoShare");
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800335
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800336 settings.setValue("dirPath", m_dirPath);
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800337 settings.setValue("username", m_username);
338 settings.setValue("sharedfoldername", m_sharedFolderName);
Jared Lindblomb4032e22013-01-17 23:50:51 -0800339}
340
341void ChronoShareGui::closeEvent(QCloseEvent* event)
342{
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800343 _LOG_DEBUG ("Close Event")
Jared Lindblomc8ffd592013-01-25 00:00:30 -0800344 this->hide();
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800345 event->ignore(); // don't let the event propagate to the base class
Jared Lindblomb4032e22013-01-17 23:50:51 -0800346}
Jared Lindblomdc845f02013-01-18 17:29:40 -0800347
348#if WAF
349#include "chronosharegui.moc"
350#include "chronosharegui.cpp.moc"
Alexander Afanasyev83a53002013-01-24 11:12:01 -0800351#endif