1 #include "tab_deck_storage.h"
2
3 #include "abstractclient.h"
4 #include "deck_loader.h"
5 #include "decklist.h"
6 #include "pb/command_deck_del.pb.h"
7 #include "pb/command_deck_del_dir.pb.h"
8 #include "pb/command_deck_download.pb.h"
9 #include "pb/command_deck_new_dir.pb.h"
10 #include "pb/command_deck_upload.pb.h"
11 #include "pb/response.pb.h"
12 #include "pb/response_deck_download.pb.h"
13 #include "pb/response_deck_upload.pb.h"
14 #include "pending_command.h"
15 #include "remotedecklist_treewidget.h"
16 #include "settingscache.h"
17
18 #include <QAction>
19 #include <QApplication>
20 #include <QFileSystemModel>
21 #include <QGroupBox>
22 #include <QHBoxLayout>
23 #include <QHeaderView>
24 #include <QInputDialog>
25 #include <QMessageBox>
26 #include <QToolBar>
27 #include <QTreeView>
28 #include <QVBoxLayout>
29
TabDeckStorage(TabSupervisor * _tabSupervisor,AbstractClient * _client)30 TabDeckStorage::TabDeckStorage(TabSupervisor *_tabSupervisor, AbstractClient *_client)
31 : Tab(_tabSupervisor), client(_client)
32 {
33 localDirModel = new QFileSystemModel(this);
34 localDirModel->setRootPath(SettingsCache::instance().getDeckPath());
35 localDirModel->sort(0, Qt::AscendingOrder);
36
37 localDirView = new QTreeView;
38 localDirView->setModel(localDirModel);
39 localDirView->setColumnHidden(1, true);
40 localDirView->setRootIndex(localDirModel->index(localDirModel->rootPath(), 0));
41 localDirView->setSortingEnabled(true);
42 localDirView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
43 localDirView->header()->setSortIndicator(0, Qt::AscendingOrder);
44
45 leftToolBar = new QToolBar;
46 leftToolBar->setOrientation(Qt::Horizontal);
47 leftToolBar->setIconSize(QSize(32, 32));
48 QHBoxLayout *leftToolBarLayout = new QHBoxLayout;
49 leftToolBarLayout->addStretch();
50 leftToolBarLayout->addWidget(leftToolBar);
51 leftToolBarLayout->addStretch();
52
53 QVBoxLayout *leftVbox = new QVBoxLayout;
54 leftVbox->addWidget(localDirView);
55 leftVbox->addLayout(leftToolBarLayout);
56 leftGroupBox = new QGroupBox;
57 leftGroupBox->setLayout(leftVbox);
58
59 rightToolBar = new QToolBar;
60 rightToolBar->setOrientation(Qt::Horizontal);
61 rightToolBar->setIconSize(QSize(32, 32));
62 QHBoxLayout *rightToolBarLayout = new QHBoxLayout;
63 rightToolBarLayout->addStretch();
64 rightToolBarLayout->addWidget(rightToolBar);
65 rightToolBarLayout->addStretch();
66
67 serverDirView = new RemoteDeckList_TreeWidget(client);
68
69 QVBoxLayout *rightVbox = new QVBoxLayout;
70 rightVbox->addWidget(serverDirView);
71 rightVbox->addLayout(rightToolBarLayout);
72 rightGroupBox = new QGroupBox;
73 rightGroupBox->setLayout(rightVbox);
74
75 QHBoxLayout *hbox = new QHBoxLayout;
76 hbox->addWidget(leftGroupBox);
77 hbox->addWidget(rightGroupBox);
78
79 aOpenLocalDeck = new QAction(this);
80 aOpenLocalDeck->setIcon(QPixmap("theme:icons/pencil"));
81 connect(aOpenLocalDeck, SIGNAL(triggered()), this, SLOT(actOpenLocalDeck()));
82 aUpload = new QAction(this);
83 aUpload->setIcon(QPixmap("theme:icons/arrow_right_green"));
84 connect(aUpload, SIGNAL(triggered()), this, SLOT(actUpload()));
85 aDeleteLocalDeck = new QAction(this);
86 aDeleteLocalDeck->setIcon(QPixmap("theme:icons/remove_row"));
87 connect(aDeleteLocalDeck, SIGNAL(triggered()), this, SLOT(actDeleteLocalDeck()));
88 aOpenRemoteDeck = new QAction(this);
89 aOpenRemoteDeck->setIcon(QPixmap("theme:icons/pencil"));
90 connect(aOpenRemoteDeck, SIGNAL(triggered()), this, SLOT(actOpenRemoteDeck()));
91 aDownload = new QAction(this);
92 aDownload->setIcon(QPixmap("theme:icons/arrow_left_green"));
93 connect(aDownload, SIGNAL(triggered()), this, SLOT(actDownload()));
94 aNewFolder = new QAction(this);
95 aNewFolder->setIcon(qApp->style()->standardIcon(QStyle::SP_FileDialogNewFolder));
96 connect(aNewFolder, SIGNAL(triggered()), this, SLOT(actNewFolder()));
97 aDeleteRemoteDeck = new QAction(this);
98 aDeleteRemoteDeck->setIcon(QPixmap("theme:icons/remove_row"));
99 connect(aDeleteRemoteDeck, SIGNAL(triggered()), this, SLOT(actDeleteRemoteDeck()));
100
101 leftToolBar->addAction(aOpenLocalDeck);
102 leftToolBar->addAction(aUpload);
103 leftToolBar->addAction(aDeleteLocalDeck);
104 rightToolBar->addAction(aOpenRemoteDeck);
105 rightToolBar->addAction(aDownload);
106 rightToolBar->addAction(aNewFolder);
107 rightToolBar->addAction(aDeleteRemoteDeck);
108
109 retranslateUi();
110
111 QWidget *mainWidget = new QWidget(this);
112 mainWidget->setLayout(hbox);
113 setCentralWidget(mainWidget);
114 }
115
retranslateUi()116 void TabDeckStorage::retranslateUi()
117 {
118 leftGroupBox->setTitle(tr("Local file system"));
119 rightGroupBox->setTitle(tr("Server deck storage"));
120
121 aOpenLocalDeck->setText(tr("Open in deck editor"));
122 aUpload->setText(tr("Upload deck"));
123 aOpenRemoteDeck->setText(tr("Open in deck editor"));
124 aDownload->setText(tr("Download deck"));
125 aNewFolder->setText(tr("New folder"));
126 aDeleteLocalDeck->setText(tr("Delete"));
127 aDeleteRemoteDeck->setText(tr("Delete"));
128 }
129
actOpenLocalDeck()130 void TabDeckStorage::actOpenLocalDeck()
131 {
132 QModelIndex curLeft = localDirView->selectionModel()->currentIndex();
133 if (localDirModel->isDir(curLeft))
134 return;
135 QString filePath = localDirModel->filePath(curLeft);
136
137 DeckLoader deckLoader;
138 if (!deckLoader.loadFromFile(filePath, DeckLoader::CockatriceFormat))
139 return;
140
141 emit openDeckEditor(&deckLoader);
142 }
143
actUpload()144 void TabDeckStorage::actUpload()
145 {
146 QModelIndex curLeft = localDirView->selectionModel()->currentIndex();
147 if (localDirModel->isDir(curLeft))
148 return;
149 QString filePath = localDirModel->filePath(curLeft);
150 QFile deckFile(filePath);
151 QFileInfo deckFileInfo(deckFile);
152 DeckLoader deck;
153 if (!deck.loadFromFile(filePath, DeckLoader::CockatriceFormat))
154 return;
155 if (deck.getName().isEmpty()) {
156 bool ok;
157 QString deckName = QInputDialog::getText(this, tr("Enter deck name"),
158 tr("This decklist does not have a name.\nPlease enter a name:"),
159 QLineEdit::Normal, deckFileInfo.completeBaseName(), &ok);
160 if (!ok)
161 return;
162 if (deckName.isEmpty())
163 deckName = tr("Unnamed deck");
164 deck.setName(deckName);
165 }
166
167 QString targetPath;
168 RemoteDeckList_TreeModel::Node *curRight = serverDirView->getCurrentItem();
169 if (!curRight)
170 return;
171 if (!dynamic_cast<RemoteDeckList_TreeModel::DirectoryNode *>(curRight))
172 curRight = curRight->getParent();
173 targetPath = dynamic_cast<RemoteDeckList_TreeModel::DirectoryNode *>(curRight)->getPath();
174
175 Command_DeckUpload cmd;
176 cmd.set_path(targetPath.toStdString());
177 cmd.set_deck_list(deck.writeToString_Native().toStdString());
178
179 PendingCommand *pend = client->prepareSessionCommand(cmd);
180 connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
181 SLOT(uploadFinished(Response, CommandContainer)));
182 client->sendCommand(pend);
183 }
184
uploadFinished(const Response & r,const CommandContainer & commandContainer)185 void TabDeckStorage::uploadFinished(const Response &r, const CommandContainer &commandContainer)
186 {
187 if (r.response_code() != Response::RespOk)
188 return;
189
190 const Response_DeckUpload &resp = r.GetExtension(Response_DeckUpload::ext);
191 const Command_DeckUpload &cmd = commandContainer.session_command(0).GetExtension(Command_DeckUpload::ext);
192
193 serverDirView->addFileToTree(resp.new_file(), serverDirView->getNodeByPath(QString::fromStdString(cmd.path())));
194 }
195
actDeleteLocalDeck()196 void TabDeckStorage::actDeleteLocalDeck()
197 {
198 QModelIndex curLeft = localDirView->selectionModel()->currentIndex();
199 if (localDirModel->isDir(curLeft))
200 return;
201
202 if (QMessageBox::warning(this, tr("Delete local file"),
203 tr("Are you sure you want to delete \"%1\"?").arg(localDirModel->fileName(curLeft)),
204 QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
205 return;
206
207 localDirModel->remove(curLeft);
208 }
209
actOpenRemoteDeck()210 void TabDeckStorage::actOpenRemoteDeck()
211 {
212 RemoteDeckList_TreeModel::FileNode *curRight =
213 dynamic_cast<RemoteDeckList_TreeModel::FileNode *>(serverDirView->getCurrentItem());
214 if (!curRight)
215 return;
216
217 Command_DeckDownload cmd;
218 cmd.set_deck_id(curRight->getId());
219
220 PendingCommand *pend = client->prepareSessionCommand(cmd);
221 connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
222 SLOT(openRemoteDeckFinished(Response, CommandContainer)));
223 client->sendCommand(pend);
224 }
225
openRemoteDeckFinished(const Response & r,const CommandContainer & commandContainer)226 void TabDeckStorage::openRemoteDeckFinished(const Response &r, const CommandContainer &commandContainer)
227 {
228 if (r.response_code() != Response::RespOk)
229 return;
230
231 const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext);
232 const Command_DeckDownload &cmd = commandContainer.session_command(0).GetExtension(Command_DeckDownload::ext);
233
234 DeckLoader loader;
235 if (!loader.loadFromRemote(QString::fromStdString(resp.deck()), cmd.deck_id()))
236 return;
237
238 emit openDeckEditor(&loader);
239 }
240
actDownload()241 void TabDeckStorage::actDownload()
242 {
243 QString filePath;
244 QModelIndex curLeft = localDirView->selectionModel()->currentIndex();
245 if (!curLeft.isValid())
246 filePath = localDirModel->rootPath();
247 else {
248 while (!localDirModel->isDir(curLeft))
249 curLeft = curLeft.parent();
250 filePath = localDirModel->filePath(curLeft);
251 }
252
253 RemoteDeckList_TreeModel::FileNode *curRight =
254 dynamic_cast<RemoteDeckList_TreeModel::FileNode *>(serverDirView->getCurrentItem());
255 if (!curRight)
256 return;
257 filePath += QString("/deck_%1.cod").arg(curRight->getId());
258
259 Command_DeckDownload cmd;
260 cmd.set_deck_id(curRight->getId());
261
262 PendingCommand *pend = client->prepareSessionCommand(cmd);
263 pend->setExtraData(filePath);
264 connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
265 SLOT(downloadFinished(Response, CommandContainer, QVariant)));
266 client->sendCommand(pend);
267 }
268
downloadFinished(const Response & r,const CommandContainer &,const QVariant & extraData)269 void TabDeckStorage::downloadFinished(const Response &r,
270 const CommandContainer & /*commandContainer*/,
271 const QVariant &extraData)
272 {
273 if (r.response_code() != Response::RespOk)
274 return;
275
276 const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext);
277 QString filePath = extraData.toString();
278
279 DeckLoader deck(QString::fromStdString(resp.deck()));
280 deck.saveToFile(filePath, DeckLoader::CockatriceFormat);
281 }
282
actNewFolder()283 void TabDeckStorage::actNewFolder()
284 {
285 QString folderName = QInputDialog::getText(this, tr("New folder"), tr("Name of new folder:"));
286 if (folderName.isEmpty())
287 return;
288
289 // '/' isn't a valid filename character on *nix so we're choosing to replace it with a different arbitrary
290 // character.
291 std::string folder = folderName.toStdString();
292 std::replace(folder.begin(), folder.end(), '/', '-');
293
294 QString targetPath;
295 RemoteDeckList_TreeModel::Node *curRight = serverDirView->getCurrentItem();
296 if (!curRight)
297 return;
298 if (!dynamic_cast<RemoteDeckList_TreeModel::DirectoryNode *>(curRight))
299 curRight = curRight->getParent();
300 RemoteDeckList_TreeModel::DirectoryNode *dir = dynamic_cast<RemoteDeckList_TreeModel::DirectoryNode *>(curRight);
301 targetPath = dir->getPath();
302
303 Command_DeckNewDir cmd;
304 cmd.set_path(targetPath.toStdString());
305 cmd.set_dir_name(folder);
306
307 PendingCommand *pend = client->prepareSessionCommand(cmd);
308 connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
309 SLOT(newFolderFinished(Response, CommandContainer)));
310 client->sendCommand(pend);
311 }
312
newFolderFinished(const Response & response,const CommandContainer & commandContainer)313 void TabDeckStorage::newFolderFinished(const Response &response, const CommandContainer &commandContainer)
314 {
315 if (response.response_code() != Response::RespOk)
316 return;
317
318 const Command_DeckNewDir &cmd = commandContainer.session_command(0).GetExtension(Command_DeckNewDir::ext);
319 serverDirView->addFolderToTree(QString::fromStdString(cmd.dir_name()),
320 serverDirView->getNodeByPath(QString::fromStdString(cmd.path())));
321 }
322
actDeleteRemoteDeck()323 void TabDeckStorage::actDeleteRemoteDeck()
324 {
325 PendingCommand *pend;
326 RemoteDeckList_TreeModel::Node *curRight = serverDirView->getCurrentItem();
327 if (!curRight)
328 return;
329 RemoteDeckList_TreeModel::DirectoryNode *dir = dynamic_cast<RemoteDeckList_TreeModel::DirectoryNode *>(curRight);
330 if (dir) {
331 QString path = dir->getPath();
332 if (path.isEmpty())
333 return;
334 if (QMessageBox::warning(this, tr("Delete remote folder"),
335 tr("Are you sure you want to delete \"%1\"?").arg(path),
336 QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
337 return;
338 Command_DeckDelDir cmd;
339 cmd.set_path(path.toStdString());
340 pend = client->prepareSessionCommand(cmd);
341 connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
342 SLOT(deleteFolderFinished(Response, CommandContainer)));
343 } else {
344 RemoteDeckList_TreeModel::FileNode *deckNode = dynamic_cast<RemoteDeckList_TreeModel::FileNode *>(curRight);
345 if (QMessageBox::warning(this, tr("Delete remote deck"),
346 tr("Are you sure you want to delete \"%1\"?").arg(deckNode->getName()),
347 QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
348 return;
349
350 Command_DeckDel cmd;
351 cmd.set_deck_id(deckNode->getId());
352 pend = client->prepareSessionCommand(cmd);
353 connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
354 SLOT(deleteDeckFinished(Response, CommandContainer)));
355 }
356
357 client->sendCommand(pend);
358 }
359
deleteDeckFinished(const Response & response,const CommandContainer & commandContainer)360 void TabDeckStorage::deleteDeckFinished(const Response &response, const CommandContainer &commandContainer)
361 {
362 if (response.response_code() != Response::RespOk)
363 return;
364
365 const Command_DeckDel &cmd = commandContainer.session_command(0).GetExtension(Command_DeckDel::ext);
366 RemoteDeckList_TreeModel::Node *toDelete = serverDirView->getNodeById(cmd.deck_id());
367 if (toDelete)
368 serverDirView->removeNode(toDelete);
369 }
370
deleteFolderFinished(const Response & response,const CommandContainer & commandContainer)371 void TabDeckStorage::deleteFolderFinished(const Response &response, const CommandContainer &commandContainer)
372 {
373 if (response.response_code() != Response::RespOk)
374 return;
375
376 const Command_DeckDelDir &cmd = commandContainer.session_command(0).GetExtension(Command_DeckDelDir::ext);
377 RemoteDeckList_TreeModel::Node *toDelete = serverDirView->getNodeByPath(QString::fromStdString(cmd.path()));
378 if (toDelete)
379 serverDirView->removeNode(toDelete);
380 }
381