1 /* --------------------------luckybackupwindow.cpp -----------------------------------------------------------------------------
2 cpp file that does all stuff needed when a signal is transmitted (eg button pressed) from the main app window
3
4 ===============================================================================================================================
5 ===============================================================================================================================
6 This file is part of "luckyBackup" project
7 Copyright, Loukas Avgeriou
8 luckyBackup is distributed under the terms of the GNU General Public License
9 luckyBackup is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 luckyBackup is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with luckyBackup. If not, see <http://www.gnu.org/licenses/>.
21
22
23 project version : Please see "main.cpp" for project version
24
25 developer : luckyb
26 last modified : 19 Jun 2016
27 ===============================================================================================================================
28 ===============================================================================================================================
29 */
30
31 //inluded headers ---------------------------------------------------------------
32 #include "luckybackupwindow.h"
33
34 #include <QProcess>
35 #include <QToolBar>
36 #include <QCloseEvent>
37 #include <QFileDialog>
38
39 #include "helpBrowser.h"
40 #include "global.h"
41 #include "winDialog.h"
42 #include "textDialog.h"
43 #include "about.h"
44 #include "modifyDialog.h"
45 #include "manage.h"
46 #include "scheduleDialog.h"
47 #include "emailDialog.h"
48
49 helpBrowser *helpbrowser;
50
51 //class luckyBackupWindow constructor=============================================================================================
luckyBackupWindow(QMainWindow * parent)52 luckyBackupWindow::luckyBackupWindow(QMainWindow *parent) : QMainWindow(parent)
53 {
54 ui.setupUi(this);
55
56 InitializeVariables();
57
58 //create directory ~/.luckyBackup including folders "logs", "profiles", "schedule", snaps if they do not exist for the current user
59 QDir profiledir(profileDir), logdir(logDir), scheduledir(scheduleDir), snapdir(snapChangesDir), emptydir(snapEmptyDir);
60 if (!profiledir.exists())
61 profiledir.mkpath(profileDir);
62 if (!logdir.exists())
63 logdir.mkpath(logDir);
64 if (!scheduledir.exists())
65 scheduledir.mkpath(scheduleDir);
66 if (!snapdir.exists())
67 snapdir.mkpath(snapChangesDir);
68 if (!emptydir.exists())
69 emptydir.mkpath(snapEmptyDir);
70 //check if the EMPTY dir is empty
71 QStringList emptyList = emptydir.entryList(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot);
72 if (emptyList.size() > 0)
73 {
74 QProcess *rmProcess;
75 rmProcess = new QProcess(this);
76 QStringList rmArgs;
77 rmArgs << "-rvf" << snapEmptyDir;
78 rmProcess -> start ("rm",rmArgs);
79 rmProcess -> waitForFinished();
80 emptydir.mkpath(snapEmptyDir);
81 }
82
83 currentUser = myHome;
84 if (currentUser == "/root")
85 {
86 currentUser = tr("super user","super user is the root user");
87 this -> setWindowTitle(appName + " - " + tr("super user mode"));
88 }
89 else
90 {
91 currentUser.remove("/home/");
92 this -> setWindowTitle(appName);
93 }
94
95 // load the user settings file. If it does not exist create it
96 QFile settingsfile(settingsFile);
97 if (settingsfile.exists())
98 loadSettings();
99 else
100 saveSettings();
101
102 createActions(); //create all actions needed
103 createToolbar(); // create tool bar
104 createMenus(); //create the top menu
105
106 retranslateUi();
107
108 //change gui to normal mode and resize it!!
109 this -> resize(mainWindowWidth, mainWindowHeight);
110 swapGUI("normal");
111
112 // Connections ----------------------------------------------------------------------------------------------------------
113 connect ( ui.pushButton_exit, SIGNAL( clicked() ), this, SLOT( exitApp() ) ); //pushbutton exit
114 connect ( ui.actionQuit, SIGNAL(triggered()), this, SLOT(exitApp())); //menu action quit
115
116 connect ( ui.comboBox_profile, SIGNAL(currentIndexChanged (const int) ), this, SLOT(profileComboChanged()));
117
118 connect ( ui.actionNew, SIGNAL(triggered()), this, SLOT(NewProfile())); //menu action newProfile
119 connect ( ui.actionRename, SIGNAL(triggered()), this, SLOT(renameCurrentProfile())); //menu action renameProfile
120 connect ( ui.actionSave, SIGNAL(triggered()), this, SLOT(savePressed())); //menu action saveProfile
121 connect ( ui.actionSchedule, SIGNAL( triggered() ), this, SLOT( schedule() ) ); //action schedule
122 connect ( ui.actionEmail, SIGNAL( triggered() ), this, SLOT( email() ) ); //action email
123 connect ( ui.actionRefresh, SIGNAL( triggered() ), this, SLOT( refreshList() ) ); //action refresh (task list)
124 connect ( ui.actionDelete, SIGNAL( triggered() ), this, SLOT( deleteCurrentProfile() ) ); //action delete (currentProfile)
125 connect ( ui.actionDefault, SIGNAL( triggered() ), this, SLOT( setDefaultProfile() ) ); //action default (set currentProfile as default)
126 connect ( ui.actionImport, SIGNAL( triggered() ), this, SLOT( importProfile() ) ); //action import profile
127 connect ( ui.actionExport, SIGNAL( triggered() ), this, SLOT( exportProfile() ) ); //action export profile
128 connect ( ui.actionDuplicate_Profile, SIGNAL( triggered() ), this, SLOT( duplicateProfile() ) ); //action duplicate profile
129 connect ( ui.actionDescription, SIGNAL(triggered()), this, SLOT(changeProfileDescription())); //menu action changeProfileDescription
130
131 connect ( ui.action_TaskAdd, SIGNAL( triggered() ), this, SLOT( add() ) ); //action add task
132 connect ( ui.action_TaskModify, SIGNAL( triggered() ), this, SLOT( modify() ) ); //action modify task
133 connect ( ui.action_TaskRemove, SIGNAL( triggered() ), this, SLOT( remove() ) ); //action remove task
134 connect ( ui.action_TaskDuplicate, SIGNAL( triggered() ), this, SLOT( duplicateTask() ) ); //action create duplicate
135 connect ( ui.action_TaskCreateRestore, SIGNAL( triggered() ), this, SLOT( AlsoCreateRestore() ) ); //action create restore
136 connect ( ui.action_TaskManageBackup, SIGNAL( triggered() ), this, SLOT( manage() ) ); //action manage backup
137
138 connect ( ui.pushButton_add, SIGNAL (clicked() ), this, SLOT(add())); //pushbutton create (task)
139 connect ( ui.pushButton_edit, SIGNAL (clicked() ), this, SLOT(modify())); //pushbutton modify (task)
140 connect ( ui.pushButton_remove, SIGNAL( clicked() ), this, SLOT( remove() ) ); //pushbutton remove (task)
141 connect ( ui.pushButton_up, SIGNAL( clicked() ), this, SLOT( moveUp() ) ); //pushbutton up
142 connect ( ui.pushButton_down, SIGNAL( clicked() ), this, SLOT( moveDown() ) ); //pushbutton down
143 connect ( ui.pushButton_start, SIGNAL( clicked() ), this, SLOT( start() ) ); //pushbutton start
144 //find a way to emit a signal when spacebar is used to change the state of an item. itemChanged does not seem to work !!
145 connect ( ui.listWidget_operations, SIGNAL( itemClicked ( QListWidgetItem*) ), this, SLOT( checkCurrentItem(QListWidgetItem *) ) );
146 connect ( ui.listWidget_operations, SIGNAL( itemChanged ( QListWidgetItem*) ), this, SLOT( taskStateChanged() ) );
147
148 connect (ui.pushButton_minimizeToTray, SIGNAL (clicked() ), this, SLOT(minimizeTray()));//pushbutton minimize to tray
149 connect (ui.pushButton_previousError, SIGNAL (clicked() ), this, SLOT(previousErrorJump()));//pushbutton jump to prev error
150 connect (ui.pushButton_nextError, SIGNAL (clicked() ), this, SLOT(nextErrorJump()));//pushbutton jump to next error
151
152 connect (ui.pushButton_InfoCollapse, SIGNAL (clicked() ), this, SLOT(hideShowInfoWindow()));//pushbutton hide/show info window
153
154 // Load the default profile as soon as the app starts or the one given as a command line argument
155 if (!runImmediately)
156 setCurrentProfile(defaultProfile); // set the defaultProfile as current
157
158 int create = createCurrentProfile(); // if it does not exist create it
159
160 loadCurrentProfile(); // load the current (default or not ) profile - this is inside functions.cpp
161
162 // *********************TESTING purposes message boxs ****************************************************************************
163 /*QMessageBox::information(this, "LB","CurrentProfile=" + currentProfile + "\ntotal tasks: " + countStr.setNum(TotalOperations));
164 QString preRelease="8"; QString preDate="09 Feb 2012";
165 QString tempOSrunning="";if (OS2running) tempOSrunning="OS2";if (WINrunning) tempOSrunning="windows";if (!notXnixRunning) tempOSrunning="*nix";
166 QMessageBox::warning(this, "luckybackup", "This is a testing version of <b>luckyBackup</b><br>"
167 "NOT to be used as an official release and NOT to be trusted for actual backups<br><br>"
168 "pre-release: <b>" + preRelease +"</b><br>version: <b>" + appVersionString + "</b><br>date: <b>"+preDate+
169
170 "</b><br>Operating system in use: <b>"+tempOSrunning +"</b><br><br> Loukas :)");*/
171 // ********************* END of TESTING ******************************************************************************************
172
173 checkCurrentItem(ui.listWidget_operations -> currentItem()); //refresh the selected (last) task as well as the menu items that depend on its type (sync/backup)
174
175 createProfileCombo(); // update the profile combobox with all existing profiles and set index to currentProfile
176 InfoData.append("<p align=\"center\"><font color=magenta><b>" + tr("Welcome to","full phrase: 'Welcome to luckyBackup'") +" "
177 + appName);
178 if (notXnixRunning)
179 InfoData.append(" :-)</font></b></p>");
180 else
181 InfoData.append(", " + currentUser + " :-)</font></b></p>");
182
183 if (create == 0)
184 InfoData.append(loadData);
185 else
186 InfoData.append(createData);
187 ui.textBrowser_info -> setText(InfoData); //update the info window
188
189 if (DryRun) // if --dry-run was given as an argument, check the relevant box
190 ui.checkBox_DryRun -> setChecked(true);
191
192 if (runImmediately)
193 start();
194
195 //variable that helps with translations
196 QString currentLanguageIs = tr("English","Do not translate this. Enter here the language of the translation in native characters instead. This is how your translation will appear under the 'language' menu.");
197
198 }
199
200 //===================================================================================================================================================
201 //------------ SLOTS --------------------------------------------------------------------------------------------------------------------------------
202 //===================================================================================================================================================
203
204 // exit =============================================================================================================================================
205 // Exits luckybackup. Warn if the profile used is not saved
exitApp()206 void luckyBackupWindow::exitApp()
207 {
208 if (NOWexecuting) //if a profile execution is in progress just minimize to tray
209 {
210 if (QSystemTrayIcon::isSystemTrayAvailable ())
211 minimizeTray();
212 return;
213 }
214 if (isProfileSaved() == 0) //if the current profile is not saved, ask the user if he/she wants to
215 return;
216 mainWindowWidth = this -> width();
217 mainWindowHeight = this -> height();
218 IsVisibleProfileComboToolbar = profileComboToolbar -> isVisible();
219 IsVisibleProfileToolbar = profileToolbar -> isVisible();
220 IsVisibleProfileStartToolbar = profileStartToolbar -> isVisible();
221 saveSettings();
222 QCoreApplication::exit(0); //quit
223 }
224
225 //do the same if the main window close button (or alt+F4) is pressed
closeEvent(QCloseEvent * event)226 void luckyBackupWindow::closeEvent(QCloseEvent *event)
227 {
228 exitApp();
229 event->ignore();
230 }
231
232 // profileComboChanged ================================================================================================================================
233 // SLOT to be executed when the profileCombo index changes
profileComboChanged()234 void luckyBackupWindow::profileComboChanged()
235 {
236 if (GoBack) //if this function is called but shouldn't be executed.
237 {
238 GoBack = false;
239 return;
240 }
241 InfoData = "";
242
243 if (isProfileSaved() == 0) //if the current profile is not saved, ask the user if he/she wants to
244 return;
245
246 //set the current profile according to the combobox reading
247 QString ComboReadFullPath = profileDir + (ui.comboBox_profile -> currentText()) + ".profile";
248 setCurrentProfile(ComboReadFullPath);
249 loadCurrentProfile(); // load the current profile
250 InfoData.append(saveData + "<br>");
251 InfoData.append(loadData);
252 ui.textBrowser_info -> setText(InfoData); //update the info window
253 loadData=""; saveData=""; createData="";
254 }
255
256 // lockToolbars ================================================================================================================================
257 // SLOT to lock the toolbars in their position
setToolbarAttrs()258 void luckyBackupWindow::setToolbarAttrs()
259 {
260 AreToolbarsLocked = actionLockToolbars->isChecked();
261
262 profileComboToolbar -> setFloatable(!AreToolbarsLocked);
263 profileComboToolbar -> setMovable(!AreToolbarsLocked);
264 profileStartToolbar -> setFloatable(!AreToolbarsLocked);
265 profileStartToolbar -> setMovable(!AreToolbarsLocked);
266 profileToolbar -> setFloatable(!AreToolbarsLocked);
267 profileToolbar -> setMovable(!AreToolbarsLocked);
268
269 shutdownToolbar -> setVisible (false);
270 shutdownToolbar -> setFloatable(!AreToolbarsLocked);
271 shutdownToolbar -> setMovable(!AreToolbarsLocked);
272
273 errorsToolbar -> setVisible (false);
274 errorsToolbar -> setFloatable(!AreToolbarsLocked);
275 errorsToolbar -> setMovable(!AreToolbarsLocked);
276
277 IsVisibleToolbarText = actionVisibleToolbarText -> isChecked();
278 if (IsVisibleToolbarText)
279 profileToolbar -> setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
280 else
281 profileToolbar -> setToolButtonStyle(Qt::ToolButtonIconOnly);
282 }
283
284 // setWinPaths ================================================================================================================================
285 // SLOT to set rsync and ssh paths for windows
setWinPaths()286 void luckyBackupWindow::setWinPaths()
287 {
288 winDialog windialog (this);
289 windialog.exec();
290 }
291
292 // savePressed ===============================================================================================================================
293 // function to execute when save pressed
savePressed()294 void luckyBackupWindow::savePressed()
295 {
296 InfoData = "";
297 saveCurrentProfile();
298 InfoData.append(saveData);
299 ui.textBrowser_info -> setText(InfoData); //update the info window
300 saveData="";
301 }
302
303 // NewProfile =====================================================================================================================================
304 // Create an new, blank profile
NewProfile()305 void luckyBackupWindow::NewProfile()
306 {
307 InfoData = "";
308 if (isProfileSaved() == 0) //if the current profile is not saved, ask the user if he/she wants to
309 return;
310
311 textDialog textdialog ("NewProfile", "", this);
312 textdialog.exec();
313 if (textdialog.getGoOn() == 0)
314 return;
315 if (textdialog.getGoOn() == 2)
316 {
317 InfoData = tr("Failed to create new profile","full phrase: 'Failed to create new profile <PROFILENAME>'")+" <b>" +
318 profileName + "</b><br><font color=red>"
319 + tr("The name you have entered contains only invalid characters") +"</font>";
320 ui.textBrowser_info -> setText(InfoData); //update the info window
321 return;
322 }
323
324 QString newProfileName = textdialog.getUserInput();
325 QString newProfile = profileDir + newProfileName + ".profile";
326
327 //check if it exists and ask to replace
328 QFile newprofile;
329 newprofile.setFileName(newProfile);
330
331 if (newprofile.exists()) //if the newprofile already exists ask to replace
332 {
333 message = tr("Profile","full phrase: 'Profile <PROFILENAME> already exists'")+" <b>" + newProfileName + "</b> " +
334 tr("already exists","full phrase: 'Profile <PROFILENAME> already exists'") + "<br>" +
335 tr("Would you like to replace it ?");
336
337 textDialog textdialogQ ("QtQuestion", message, this);
338 textdialogQ.exec();
339
340 if (textdialogQ.getGoOn() > 0) //if user answers yes
341 {
342 if (!newprofile.remove()) // delete the old profile or display a message if you can't
343 {
344 InfoData = "<font color=red><b>" + tr("ERROR") + "</font></b><br>" +
345 tr("Failed to replace profile","full phrase: 'Failed to replace profile <PROFILENAME>'")+
346 " <b>" + newProfileName + "</b><br><font color=red>"
347 + profile.errorString() +"</font>";
348 ui.textBrowser_info -> setText(InfoData); //update the info window
349 return;
350 }
351 }
352 else
353 return;
354 }
355
356 setCurrentProfile(newProfile);
357 createCurrentProfile(); // try to create it (also calls createProfileCombo)
358 loadCurrentProfile(); // load the current profile
359 InfoData.append(createData);
360 ui.textBrowser_info -> setText(InfoData); //update the info window
361 loadData=""; saveData=""; createData="";
362 }
363
364 // renameCurrentProfile =============================================================================================================================
365 // rename the current profile
renameCurrentProfile()366 void luckyBackupWindow::renameCurrentProfile()
367 {
368 InfoData="";
369
370 textDialog textdialog ("RenameProfile", profileName, this);
371 textdialog.exec();
372 if (textdialog.getGoOn() == 0)
373 return;
374
375 if (textdialog.getGoOn() == 2)
376 {
377 InfoData = tr("Failed to rename profile","full phrase: 'Failed to rename profile <PROFILENAME>'")+
378 " <b>" + profileName + "</b><br><font color=red>"
379 + "The name you have entered contains only invalid characters" +"</font>";
380 ui.textBrowser_info -> setText(InfoData); //update the info window
381 return;
382 }
383
384 if (textdialog.getGoOn() == 3) //if the new profile name is the same with the old one do nothing
385 {
386 InfoData.append(tr("profile","full phrase: 'profile <PROFILENAME> renamed successfully to <NEWPROFILENAME>'")
387 + " <b>" + profileName + "</b><br>...<font color=green>"
388 + tr("renamed successfully to","full phrase: 'profile <PROFILENAME> renamed successfully to <NEWPROFILENAME>'") +
389 "</font> <b>" + profileName +"</b>");
390 ui.textBrowser_info -> setText(InfoData); //update the info window
391 return;
392 }
393
394 QString newProfileName = textdialog.getUserInput();
395 QString newProfile = profileDir + newProfileName + ".profile";
396
397 //check if it exists and ask to replace
398 QFile newprofile;
399 newprofile.setFileName(newProfile);
400
401 if (newprofile.exists()) //if the newprofile already exists ask to replace
402 {
403 message = tr("Profile","full phrase: 'Profile <PROFILENAME> already exists'")+" <b>" + newProfileName + "</b> " +
404 tr("already exists","full phrase: 'Profile <PROFILENAME> already exists'") + "<br>" +
405 tr("Would you like to replace it ?");
406
407 textDialog textdialogQ ("QtQuestion", message, this);
408 textdialogQ.exec();
409
410 if (textdialogQ.getGoOn() > 0) //if user answers yes
411 {
412 if (!newprofile.remove()) // delete the old profile or display a message if you can't
413 {
414 InfoData = "<font color=red><b>" + tr("ERROR") + "</font></b><br>" +
415 tr("Failed to replace profile",
416 "full phrase: 'Failed to replace profile <PROFILENAME>'")+" <b>" + newProfileName + "</b><br><font color=red>"
417 + newprofile.errorString() +"</font>";
418 ui.textBrowser_info -> setText(InfoData); //update the info window
419 return;
420 }
421 }
422 else
423 return;
424 }
425
426 if (!profile.rename(newProfile)) //try to rename the current profile
427 {
428 InfoData = "<font color=red><b>" + tr("ERROR") + "</font></b><br>" +
429 tr("Failed to rename profile",
430 "full phrase: 'Failed to rename profile <PROFILENAME>'")+" <b>" + profileName + "</b><br><font color=red>"
431 + profile.errorString() +"</font>";
432 ui.textBrowser_info -> setText(InfoData); //update the info window
433 return;
434 }
435 if (currentProfile == defaultProfile)
436 {
437 InfoData.append(tr("default profile","full phrase: 'default profile <PROFILENAME> renamed successfully to <NEWPROFILENAME>'."));
438 defaultProfile = newProfile;
439 saveSettings();
440 }
441 else
442 InfoData.append(tr("profile", "full phrase: 'profile <PROFILENAME> renamed successfully to <NEWPROFILENAME>'"));
443
444 InfoData.append(" <b>" + profileName + "</b><br>...<font color=green>" + tr("renamed successfully to",
445 "full phrase: '(default) profile <PROFILENAME> renamed successfully to <NEWPROFILENAME>'") + "</font> <b>" + newProfileName +"</b>");
446
447 // update all relevant snap .changes as well as log files
448 if (arrangeLogSnap(1,"rename",newProfileName))
449 InfoData.append("<br><br>" + tr("All relevant files (logs etc) have also been updated"));
450 else
451 InfoData.append("<br><br>" + tr("Failed to update all relevant files (logs etc)"));
452
453 setCurrentProfile(newProfile);
454 createProfileCombo(); // update the profile combobox with all existing profiles and set index to currentProfile
455 loadCurrentProfile(); // load the current profile
456 ui.textBrowser_info -> setText(InfoData); //update the info window
457 loadData=""; saveData=""; createData="";
458
459 }
460 // deleteProfile ======================================================================================================================================
461 // deletes the current profile
deleteCurrentProfile()462 void luckyBackupWindow::deleteCurrentProfile()
463 {
464 InfoData="";
465 if (currentProfile == defaultProfile)
466 message = tr("Are you sure you want to delete the default profile",
467 "full phrase: 'Are you sure you want to delete the default profile: <PROFILENAME> ? (a new blank one, with the same name, will be created)'")+
468 ": <b>" + profileName + "</b> ?<br>(" +
469 tr("a new blank one, with the same name, will be created",
470 "full phrase: 'Are you sure you want to delete the default profile: <PROFILENAME> ? (a new blank one, with the same name, will be created)'") +")";
471 else
472 message = tr("Are you sure you want to delete profile",
473 "full phrase: 'Are you sure you want to delete profile: <PROFILENAME> ?'")+": <b>" + profileName + "</b> ?";
474
475 textDialog textdialogQ ("QtQuestion", message, this);
476 textdialogQ.exec();
477
478 if (textdialogQ.getGoOn() > 0) //if user answers yes
479 {
480 savedProfile = true; //assume the profile is saved
481 //try to delete the profile
482 if (!profile.remove())
483 {
484 InfoData.append("<font color=red><b>" + tr("ERROR") + "</font></b><br>" +
485 tr("Failed to delete profile",
486 "full phrase: 'Failed to delete profile <PROFILENAME>'")+": <b>" + profileName + "</b><br><font color=red>"
487 + profile.errorString() +"</font><br>");
488 ui.textBrowser_info -> setText(InfoData); //update the info window
489 return;
490 }
491
492 InfoData.append(tr("Profile","full phrase: 'Profile <PROFILENAME> deleted successfully'") +
493 ": <b>" + profileName + "</b><br>...<font color=green>" +
494 tr("deleted successfully","full phrase: 'Profile <PROFILENAME> deleted successfully'") + " !!</font><br>");
495
496 // delete all relevant snap .changes as well as log files
497 if (arrangeLogSnap(1,"delete",profileName))
498 InfoData.append("<br>" + tr("All relevant files (logs etc) have also been deleted") + "<br>");
499 else
500 InfoData.append("<br>" + tr("Failed to delete all relevant files (logs etc)") + "<br>");
501
502 // Load the default profile
503 setCurrentProfile(defaultProfile); // set the defaultProfile as current
504 int create = createCurrentProfile(); // if it does not exist create it
505 loadCurrentProfile(); // load the current (default) profile
506 createProfileCombo(); // update the profile combobox with all existing profiles and set index to currentProfile
507
508 if (create == 0)
509 InfoData.append(loadData);
510 else
511 InfoData.append(createData);
512 ui.textBrowser_info -> setText(InfoData); //update the info window
513 loadData=""; saveData=""; createData="";
514 }
515 }
516
517
518 // setDefaultProfile ================================================================================================================================
519 // sets the current profile as default
setDefaultProfile()520 void luckyBackupWindow::setDefaultProfile()
521 {
522 InfoData = "";
523
524 defaultProfile = currentProfile;
525 saveSettings();
526 InfoData.append(tr("Profile","full phrase: 'Profile <PROFILENAME> set as default'") + ": <b>" + profileName + "</b><br>...<font color=green>" + tr("set as default","full phrase: 'Profile <PROFILENAME> set as default'") + " !!</font><br>");
527 ui.textBrowser_info -> setText(InfoData); //update the info window
528 }
529
530 // duplicateProfile ================================================================================================================================
531 // duplicates the current profile
duplicateProfile()532 void luckyBackupWindow::duplicateProfile()
533 {
534 InfoData="";
535
536 textDialog textdialog ("RenameProfile", profileName, this);
537 textdialog.exec();
538 if (textdialog.getGoOn() == 0)
539 return;
540
541 if (textdialog.getGoOn() == 2)
542 {
543 InfoData = tr("Failed to duplicate profile","full phrase: 'Failed to duplicate profile <PROFILENAME>'")+
544 " <b>" + profileName + "</b><br><font color=red>"
545 + "The name you have entered contains only invalid characters" +"</font>";
546 ui.textBrowser_info -> setText(InfoData); //update the info window
547 return;
548 }
549
550 QString duplicateProfileName = textdialog.getUserInput();
551 QString duplicateProfile = profileDir + duplicateProfileName + ".profile";
552
553 //check if it exists and ask to replace
554 QFile duplicateprofile;
555 duplicateprofile.setFileName(duplicateProfile);
556
557 if (duplicateprofile.exists()) //if the duplicateprofile already exists ask to replace
558 {
559 message = tr("Profile","full phrase: 'Profile <PROFILENAME> already exists'")+" <b>" + duplicateProfileName + "</b> " +
560 tr("already exists","full phrase: 'Profile <PROFILENAME> already exists'") + "<br>" +
561 tr("Would you like to replace it ?");
562 textDialog textdialogQ ("QtQuestion", message, this);
563 textdialogQ.exec();
564
565 if (textdialogQ.getGoOn() > 0) //if user answers yes
566 {
567 if (!duplicateprofile.remove()) // delete the old profile or display a message if you can't
568 {
569 InfoData = "<font color=red><b>" + tr("ERROR") + "</font></b><br>" +
570 tr("Failed to replace profile",
571 "full phrase: 'Failed to replace profile <PROFILENAME>'")+" <b>" + duplicateProfileName + "</b><br><font color=red>"
572 + duplicateprofile.errorString() +"</font>";
573 ui.textBrowser_info -> setText(InfoData); //update the info window
574 return;
575 }
576 }
577 else
578 return;
579 }
580
581 if (!saveProfile(duplicateProfile)) //try to save the new (duplicate) profile
582 {
583 InfoData = "<font color=red><b>" + tr("ERROR") + "</font></b><br>" +
584 tr("Failed to duplicate profile","full phrase: 'Failed to duplicate profile <PROFILENAME> as <FILENAME>'")+
585 " <b>" + profileName + "</b><br>"
586 +tr("as","full phrase: 'Failed to duplicate profile <PROFILENAME> as <FILENAME>'")+
587 " <b>" + duplicateProfileName +"</b><br><font color=red>"
588 + profile.errorString() +"</font>";
589 ui.textBrowser_info -> setText(InfoData); //update the info window
590 setCurrentProfile(currentProfile); //reset all currentProfile variables
591 return;
592 }
593
594 InfoData.append(tr("Profile","full phrase: 'Profile <PROFILENAME> duplicated successfully as <FILENAME>'") + ": <b>" +
595 profileName + "</b><br>...<font color=green>"
596 + tr("duplicated successfully as","full phrase: 'Profile <PROFILENAME> duplicated successfully as <FILENAME>'") +
597 "</font> <b>" + duplicateProfileName +"</b>");
598
599 // duplicate all relevant snap .changes as well as log files
600 if (arrangeLogSnap(1,"duplicate",duplicateProfileName))
601 InfoData.append("<br><br>" + tr("All relevant files (logs etc) have also been duplicated"));
602 else
603 InfoData.append("<br><br>" + tr("Failed to duplicate all relevant files (logs etc)"));
604
605 setCurrentProfile(currentProfile); //reset all currentProfile variables
606 createProfileCombo(); // update the profile combobox with all existing profiles and set index to currentProfile
607 ui.textBrowser_info -> setText(InfoData); //update the info window
608 loadData=""; saveData=""; createData="";
609 }
610
611 // changeProfileDescription ================================================================================================================================
612 // Changes the profile description
changeProfileDescription()613 void luckyBackupWindow::changeProfileDescription()
614 {
615 InfoData="";
616
617 textDialog textdialog ("ProfileDescription", profileDescription, this);
618 textdialog.exec();
619
620 if (textdialog.getGoOn() == 0)
621 return;
622
623 profileDescription = textdialog.getUserInput();
624
625 QString profileDescriptionDisplay = profileDescription;
626 profileDescriptionDisplay.replace("\n","<br>");
627
628
629 InfoData.append(tr("The description of profile","full phrase: 'The description of profile <PROFILENAME> set to: <DESCRIPTION>'") + " <b>" + profileName + "</b> " + tr("set to","full phrase: 'The description of profile <PROFILENAME> set to: <DESCRIPTION>'") +
630 ":<br>" + profileDescriptionDisplay);
631
632 ui.textBrowser_info -> setText(InfoData); //update the info window
633 savedProfile = false; //change profile status to "unsaved"
634 ui.actionSave -> setEnabled(true);
635 }
636
637 // duplicateTask ================================================================================================================================
638 // duplicates the current task (creates a new task - same as selected - and opens modify dialog)
duplicateTask()639 void luckyBackupWindow::duplicateTask()
640 {
641 modifyOK = false;
642 modifyConnected = false;
643 newTaskThisIs = true;
644
645 currentOperation = ui.listWidget_operations -> currentRow(); //current task list row number
646 if (currentOperation < 0) //if nothing is selected do nothing
647 {
648 InfoData = tr("Please select a task to duplicate first") + " !!";
649 ui.textBrowser_info -> setText(InfoData);
650 return;
651 }
652 int oldCurrentOperation = currentOperation;
653
654 TotalOperations = ui.listWidget_operations -> count(); //Get the Operations list size
655 if ( (TotalOperations) >= (maxOperations-1) ) //if the maxOperations limit-1 is reached
656 {
657 textDialog textdialogW ("QtWarning",
658 tr("You have reached the maximum limit of supported tasks")+" <br><br>" +
659 tr("You have to remove a task if you wish to add another !!"), this);
660 textdialogW.exec();
661 return;
662 }
663
664 currentOperation = TotalOperations;
665
666 //Create a new array item identical to the one just created
667 operation *tempOp = new operation;
668 *tempOp = *Operation[oldCurrentOperation];
669 Operation[currentOperation] = tempOp;
670
671 // Reset the last execution time/errors & clear its snapshots list
672 QDateTime newTime; // empty time variable
673 Operation[currentOperation] -> SetLastExecutionTime (newTime);
674 Operation[currentOperation] -> SetLastExecutionErrors (-1);
675 Operation[currentOperation] -> ClearSnapshotsList();
676
677 //Change the task name and remove any RESTORE connections
678 Operation[currentOperation] -> SetName ((Operation[currentOperation] -> GetName()) + " DUPLICATE");
679 Operation[currentOperation] -> SetConnectRestore("");
680
681 //add a new item in the operations list
682 ui.listWidget_operations -> addItem( Operation[currentOperation] -> GetName() );
683 ui.listWidget_operations -> setCurrentRow(currentOperation);
684 ui.listWidget_operations -> currentItem() -> setCheckState(Qt::Unchecked);
685 TotalOperations = ui.listWidget_operations -> count(); //set the TotalOperations to what it is now
686
687 saveOrNot=false;
688 modify(); //open the modify dialog for the new task, false == do not save the result
689 saveOrNot = true;
690
691 if (modifyOK)
692 {
693 savedProfile = false; //change profile status to "unsaved"
694 ui.actionSave -> setEnabled(true);
695 }
696 else
697 {
698 //remove already created DUPLICATE TASK from operations list
699 ui.listWidget_operations -> takeItem(currentOperation); //take out the selected item from the list
700 TotalOperations = ui.listWidget_operations -> count(); //TotalOperations takes the new value (old - 1)
701 }
702 }
703
704 // AlsoCreateRestore ================================================================================================================================
705 //create another operation for RESTORE
AlsoCreateRestore()706 void luckyBackupWindow::AlsoCreateRestore()
707 {
708 newTaskThisIs = true;
709 int oldCurrentOperation = ui.listWidget_operations -> currentRow(); //current task list row number;
710
711 if (oldCurrentOperation < 0) //if nothing is selected do nothing
712 {
713 InfoData = tr("Please select a task first") + " !!";
714 ui.textBrowser_info -> setText(InfoData);
715 return;
716 }
717
718 TotalOperations = ui.listWidget_operations -> count(); //Get the Operations list size
719 if ( (TotalOperations) >= (maxOperations-1) ) //if the maxOperations limit-1 is reached
720 {
721 textDialog textdialogW ("QtWarning",
722 tr("You have reached the maximum limit of supported tasks")+" <br><br>" +
723 tr("You have to remove a task if you wish to add another !!"), this);
724 textdialogW.exec();
725 return;
726 }
727
728 currentOperation = TotalOperations;
729
730 //Create a new array item identical to the one just created
731 operation *tempOp = new operation;
732 *tempOp = *Operation[oldCurrentOperation];
733 Operation[currentOperation] = tempOp;
734
735 // Reset the last execution time/errors & clear its snapshots list
736 QDateTime newTime; // empty time variable
737 Operation[currentOperation] -> SetLastExecutionTime (newTime);
738 Operation[currentOperation] -> SetLastExecutionErrors (-1);
739 Operation[currentOperation] -> ClearSnapshotsList();
740
741 //Change its name, source, destination, update checkbox, Remote Host radiobuttons
742 Operation[currentOperation] -> SetName ("RESTORE - " + (Operation[currentOperation] -> GetName()));
743 Operation[currentOperation] -> SetOptionsUpdate(false);
744 Operation[currentOperation] -> SetOptionsDelete(false);
745 Operation[currentOperation] -> SetKeepSnapshots(1);
746 Operation[currentOperation] -> SetRemoteDestination(Operation[oldCurrentOperation]-> GetRemoteSource());
747 Operation[currentOperation] -> SetRemoteSource(Operation[oldCurrentOperation]-> GetRemoteDestination());
748 QString sourceDir = Operation[oldCurrentOperation] -> GetDestination();
749 QString destDir = Operation[oldCurrentOperation] -> GetSource();
750
751 if (Operation[currentOperation] -> GetTypeDirName())
752 {
753 if (WINrunning && Operation[currentOperation] -> GetRemote())
754 {
755 sourceDir.append(destDir.right(destDir.size() - destDir.lastIndexOf(XnixSLASH) - 1));
756 destDir.chop(destDir.size() - destDir.lastIndexOf(XnixSLASH) - 1);
757 }
758 else
759 {
760 sourceDir.append(destDir.right(destDir.size() - destDir.lastIndexOf(SLASH) - 1));
761 destDir.chop(destDir.size() - destDir.lastIndexOf(SLASH) - 1);
762 }
763 }
764
765 Operation[currentOperation] -> SetSource (sourceDir);
766 Operation[currentOperation] -> SetDestination (destDir);
767
768 //add a new item in the operations list
769 ui.listWidget_operations -> addItem( Operation[currentOperation] -> GetName() );
770 ui.listWidget_operations -> setCurrentRow(currentOperation);
771 ui.listWidget_operations -> currentItem() -> setCheckState(Qt::Unchecked);
772 TotalOperations = ui.listWidget_operations -> count(); //set the TotalOperations to what it is now
773
774 textDialog textdialogW ("QtWarning",
775 tr("You have asked for a RESTORE task to be created","'create restore' message line 1/4")+"<br><br>"+
776 tr("Please have a good look at the following task properties dialog","'create restore' message line 2/4")+" <br>"+
777 tr("and change anything you wish before proceeding","'create restore' message line 3/4")+" <br><br>"+
778 tr("Please check 'Task name', 'source', 'destination' and especially the 'Delete files on the destination'' & 'skip newer destination files' check-boxes (advanced)","'create restore' message line 4/4")+"<br>",
779 this);
780 textdialogW.exec();
781
782 modifyConnected = true;
783 saveOrNot = false;
784 modify(); //open the modify dialog for the new operation to make sure everything is ok, false == do not save the result
785 saveOrNot = true;
786
787 if (modifyOK) //connect the operation with its RESTORE duplicate
788 {
789 Operation[currentOperation] -> SetConnectRestore(Operation[oldCurrentOperation] -> GetName());
790 Operation[oldCurrentOperation] -> SetConnectRestore(Operation[currentOperation] -> GetName());
791 savedProfile = false; //change profile status to "unsaved"
792 ui.actionSave -> setEnabled(true);
793 }
794 else
795 {
796 //remove already created RESTORE operation from operations list
797 ui.listWidget_operations -> takeItem(currentOperation); //take out the selected item from the list
798 TotalOperations = ui.listWidget_operations -> count(); //TotalOperations takes the new value (old - 1)
799 }
800 }
801
802 // exportProfile ================================================================================================================================
803 // exports the current profile to another location
exportProfile()804 void luckyBackupWindow::exportProfile()
805 {
806 InfoData = "";
807
808 // Display a save dialog for a directory to export the profile to
809 QString exportProfileName = QFileDialog::getExistingDirectory(this,
810 appName + " - " + tr("Select export directory","this is a dialog title for selecting a directory to export a profile to"), SLASH,
811 QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks) + SLASH + profileName;
812
813 if ( exportProfileName == "") //if cancel is pressed at the file dialog, do nothing
814 return;
815
816 // put the ".profile" extension if its not there
817 if (!exportProfileName.endsWith(".profile", Qt::CaseInsensitive))
818 exportProfileName.append(".profile" + SLASH);
819
820
821 if (!exportFullProfile(exportProfileName,"ExportFullProfile")) //try to save/export the new profile
822 {
823 InfoData = "<font color=red><b>" + tr("ERROR") + "</font></b><br>" +
824 tr("Failed to export profile","full phrase: 'Failed to export profile <PROFILENAME> to <DIRNAME>'")+
825 " <b>" + profileName + "</b><br>"
826 +tr("to","full phrase: 'Failed to export profile <PROFILENAME> to <DIRNAME>'")+
827 " <b>" + exportProfileName +"</b>";
828 ui.textBrowser_info -> setText(InfoData); //update the info window
829 setCurrentProfile(currentProfile); //reset all currentProfile variables
830 return;
831 }
832
833 InfoData.append(tr("Profile","full phrase: 'Profile <PROFILENAME> exported successfully to <DIRNAME>'") + ": <b>" +
834 profileName + "</b><br>...<font color=green>"
835 + tr("exported successfully to","full phrase: 'Profile <PROFILENAME> exported successfully to <DIRNAME>'") +
836 "</font> <b>" + exportProfileName +"</b>");
837
838 ui.textBrowser_info -> setText(InfoData); //update the info window
839 setCurrentProfile(currentProfile); //reset all currentProfile variables
840 createProfileCombo(); // update the profile combobox (in case profile was exported at ~/.luckyBackup/profiles) and set index to currentProfile
841 }
842
843 // importProfile ================================================================================================================================
844 // imports a profile (+logs +snaps) to the profile directory
importProfile()845 void luckyBackupWindow::importProfile()
846 {
847 InfoData = "";
848
849 // This holds the full path of the profile to get imported directory (eg /media/exported/default.profile)
850 QString importProfilePath = QFileDialog::getExistingDirectory(this,
851 appName + " - " + tr("Import Profile","this is a dialog title"), SLASH,
852 QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
853
854 if ( importProfilePath == "") //if cancel is pressed at the file dialog, do nothing
855 return;
856
857 // check if the directory selected by the user contains valid profile data
858 QDir importprofile;
859 importprofile.setPath(importProfilePath);
860 QStringList dirsToFilter; dirsToFilter << "profiles" << "logs" <<"snaps";
861 QStringList importPprofileContents = importprofile.entryList(dirsToFilter,QDir::AllDirs,QDir::NoSort);
862 if (!importPprofileContents.contains("profiles")) // check if there exists a "profile" dir
863 {
864 InfoData = tr("Failed to import profile","full phrase: 'Failed to import profile <PROFILENAME>'")+
865 " <b>" + importProfilePath + "</b><br><font color=red>"
866 + tr("The directory you have selected does not contain valid profile data") +"</font>";
867 ui.textBrowser_info -> setText(InfoData); //update the info window
868 return;
869 }
870
871 // Check if the profile to import already exists
872 QString newProfileName = importProfilePath; // newProfileName holds the final name of the profile that is going to get imported (eg "default2")
873 newProfileName = newProfileName.right(newProfileName.size() - newProfileName.lastIndexOf(SLASH) - 1);
874 if (newProfileName.endsWith(".profile"))
875 newProfileName.chop(8);
876 QString importProfileName = newProfileName; //This holds the name of the profile to import (eg "default")
877
878 //newProfile holds the final full path of the .profile file (eg ~/.luckyBackup/profiles/default2.profile)
879 QString newProfile = profileDir + newProfileName + ".profile";
880 QFile newprofile;
881 newprofile.setFileName(newProfile);
882
883 while (newprofile.exists()) //if the newprofile already exists ask to rename or cancel
884 {
885 textDialog textdialog ("ImportProfile", newProfileName,this);
886 textdialog.exec();
887 newProfileName = textdialog.getUserInput();
888
889 if (textdialog.getGoOn() == 0)
890 return;
891 if (textdialog.getGoOn() == 2)
892 {
893 InfoData = tr("Failed to import profile","full phrase: 'Failed to import profile <PROFILENAME>'")+
894 " <b>" + importProfileName + "</b><br><font color=red>"
895 + tr("The name you have entered contains only invalid characters") +"</font>";
896 ui.textBrowser_info -> setText(InfoData); //update the info window
897 return;
898 }
899 newProfile = profileDir + newProfileName + ".profile";
900 newprofile.setFileName(newProfile);
901 }
902
903 int ExitCodeImportProfile = importFullProfile(importProfilePath,newProfileName);
904 //QMessageBox::information(this, "LB","Exit code=" + countStr.setNum(ExitCodeImportProfile)); // TESTING
905 // if ExitCodeImportProfile != 1
906 if ( (ExitCodeImportProfile == 0) || (ExitCodeImportProfile == 30) || (ExitCodeImportProfile == 20) || (ExitCodeImportProfile == 10) )
907 {
908 createProfileCombo();
909 InfoData.append(tr("Profile",
910 "full phrase: 'Profile <PROFILENAME> imported successfully as <NEWPROFILENAME> and added at the profile list'") +
911 ": <b>" + importProfileName + "</b><br>...<font color=green>"
912 + tr("imported successfully",
913 "full phrase: 'Profile <PROFILENAME> imported successfully as <NEWPROFILENAME> and added at the profile list'") +
914 "</font> " + tr("as","full phrase: 'Profile <PROFILENAME> imported successfully as <NEWPROFILENAME> and added at the profile list'")
915 + " <b>" + newProfileName + "</b><br><font color=green>"
916 + tr("and added at the profile list",
917 "full phrase: 'Profile <PROFILENAME> imported successfully as <NEWPROFILENAME> and added at the profile list'") + "</font>");
918 if (ExitCodeImportProfile == 30)
919 InfoData.append("<br><font color=red>" + tr("Errors occurred during snapshots and logfiles transfer") +"</font>");
920 if (ExitCodeImportProfile == 20)
921 InfoData.append("<br><font color=red>" + tr("Errors occurred during snapshots transfer") +"</font>");
922 if (ExitCodeImportProfile == 10)
923 InfoData.append("<br><font color=red>" + tr("Errors occurred during logfiles transfer") +"</font>");
924 }
925 else // ExitCodeImportProfile == 1
926 InfoData = tr("Failed to import profile","full phrase: 'Failed to import profile <PROFILENAME>'")+" <b>" + importProfileName +
927 "</b><br><font color=red>" +tr("Errors occurred during the profile file transfer") +"</font>";
928 ui.textBrowser_info -> setText(InfoData); //update the info window
929 }
930
931 // setLanguage =====================================================================================================================================
932 // changes the language of the application
setLanguage(QAction * action)933 void luckyBackupWindow::setLanguage(QAction *action)
934 {
935 QString currentLocale = action -> data().toString();
936 transDir.setPath(relativeTransDir);
937 QStringList transContQm = transDir.entryList ( QStringList("luckybackup*.qm"), QDir::Files, QDir::NoSort); // list of .qm files inside transdir
938 if ( (transDir.exists()) && (!transContQm.isEmpty()) )
939 appTranslator.load(QString("luckybackup_") + currentLocale, relativeTransDir);
940 else
941 appTranslator.load(QString("luckybackup_") + currentLocale, systemTransDir);
942
943 translator_qt.load(QString("qt_") + currentLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
944
945 defaultLanguage = currentLocale;
946 retranslateUi();
947 }
948
949 // hideShowInfoWindow ===============================================================================================================================
950 // Shows / hides the information window
hideShowInfoWindow()951 void luckyBackupWindow::hideShowInfoWindow()
952 {
953 IsVisibleInfoWindow = !(ui.pushButton_InfoCollapse -> isChecked());
954 if (IsVisibleInfoWindow)
955 {
956 ui.pushButton_InfoCollapse -> setToolTip(tr("Hide information window","hide/show information window button tooltip"));
957 ui.pushButton_InfoCollapse -> setIcon(QIcon(":/luckyPrefix/collapse.png"));
958 if (guiModeNormal)
959 ui.textBrowser_info -> setVisible (true);
960 else
961 ui.nowDoing -> setVisible (true);
962 }
963 else
964 {
965 ui.pushButton_InfoCollapse -> setToolTip(tr("Show information window","hide/show information window button tooltip"));
966 ui.pushButton_InfoCollapse -> setIcon(QIcon(":/luckyPrefix/collapseUP.png"));
967 if (guiModeNormal)
968 ui.textBrowser_info -> setVisible (false);
969 else
970 ui.nowDoing -> setVisible (false);
971 }
972 }
973
974 // help =============================================================================================================================================
975 // Shows the "help" information window
976 // This is a modeless dialog so that users can interact with it together with the main app
help()977 void luckyBackupWindow::help()
978 {
979 if (helpURL.toString() == "Does_not_exist")
980 {
981 InfoData = "<font color=red><b>" + tr("ERROR") + "</font></b><br>" +
982 tr("Could not locate the file","full phrase: 'Could not locate the file <FILENAME>'")+": <b>" + relativeManual +"</b><br> :-(";
983 ui.textBrowser_info -> setText(InfoData); //update the info window
984 return;
985 }
986
987 if (!helpbrowser)
988 helpbrowser = new helpBrowser (helpURL);
989
990 if (helpbrowser->isHidden())
991 helpbrowser -> show();
992
993 helpbrowser -> scrollToChapter(manualChapter); // The manualChapter variable will scroll to the relevant chapter
994
995 helpbrowser -> raise();
996 helpbrowser -> activateWindow();
997 }
998
999 // about ============================================================================================================================================
1000 // Shows the "about" information window
about()1001 void luckyBackupWindow::about()
1002 {
1003 aboutDialog aboutdialog(licenseURL);
1004 aboutdialog.exec();
1005 }
1006
1007 // add =============================================================================================================================================
1008 // Creates a new operation by calling the modifyDialog
add()1009 void luckyBackupWindow::add()
1010 {
1011 modifyOK = false;
1012 modifyConnected = false;
1013 newTaskThisIs = true;
1014 TotalOperations = ui.listWidget_operations -> count(); //Get the Operations list size
1015 currentOperation = TotalOperations;
1016
1017 if ( (TotalOperations) >= (maxOperations-1) ) //if the maxOperations limit-1 is reached
1018 {
1019 textDialog textdialogW ("QtWarning",
1020 tr("You have reached the maximum limit of supported tasks")+" <br><br>" +
1021 tr("You have to remove a task if you wish to add another !!"), this);
1022 textdialogW.exec();
1023 return;
1024 }
1025
1026 //open the modify dialog and create "Operation array" item at position currentOperation
1027 modifyDialog modifydialog(currentOperation);
1028 modifydialog.exec();
1029
1030 if (modifyOK) //if all went ok - add new operation
1031 {
1032 //add a new item in the operations list
1033 ui.listWidget_operations -> addItem( Operation[currentOperation] -> GetName() );
1034 ui.listWidget_operations -> setCurrentRow(currentOperation);
1035 ui.listWidget_operations -> currentItem() -> setCheckState(Qt::Unchecked);
1036 checkCurrentItem(ui.listWidget_operations -> currentItem());
1037 TotalOperations = ui.listWidget_operations -> count(); //set the TotalOperations to what it is now
1038 savedProfile = false; //change profile status to "unsaved"
1039 ui.actionSave -> setEnabled(true);
1040 }
1041 }
1042
1043 // modify ==========================================================================================================================================
1044 // Modifies an existing operation by calling the modifyDialog
1045 // Will also save the profile according to saveOrNot
modify()1046 void luckyBackupWindow::modify()
1047 {
1048 modifyOK = false;
1049 newTaskThisIs = false;
1050 currentOperation = ui.listWidget_operations -> currentRow(); //current operations list row number
1051 if (currentOperation < 0) //if nothing is selected do nothing
1052 {
1053 InfoData = tr("Please select a task to modify first") + " !!";
1054 ui.textBrowser_info -> setText(InfoData);
1055 return;
1056 }
1057
1058 QString tempConnect = Operation[currentOperation] -> GetConnectRestore();
1059 if ( (tempConnect != "") && (!modifyConnected) ) //the operations is connected and is a not new RESTORE operation
1060 modifyConnected = true;
1061 int connectPosition=0;
1062 if (tempConnect != "") //if this op is already connected with another op, (pop up a message & )hold the connection's position
1063 {
1064 count=0;
1065 while (count<TotalOperations)
1066 { //get the connected operation position at connectPosition
1067 if (Operation[count]->GetName()==tempConnect) connectPosition=count;
1068 count++;
1069 }
1070 }
1071
1072 QString oldTaskName = Operation[currentOperation] -> GetName(); // the original task name wil become handy in case it changes
1073
1074 //open the modify dialog and modify "Operation array" item at position currentOperation
1075 modifyDialog modifydialog(currentOperation);
1076 modifydialog.exec();
1077
1078 if (modifyOK) //if all went ok - modify existing operation
1079 {
1080 Qt::CheckState isIncluded = ui.listWidget_operations -> currentItem() -> checkState(); //get the include checkbox state
1081 QString newTaskName = Operation[currentOperation] -> GetName(); // the new task name
1082 ui.listWidget_operations -> takeItem(currentOperation); //take out the selected item from the list
1083 //insert a new one at the same position with the new name
1084 ui.listWidget_operations -> insertItem(currentOperation, newTaskName);
1085 ui.listWidget_operations -> setCurrentRow(currentOperation); //highlight this row
1086 ui.listWidget_operations -> currentItem() -> setCheckState(isIncluded); //set the include checkbox as it was
1087 Operation[currentOperation] -> SetConnectRestore(tempConnect); //set the connection to what it was
1088 if (tempConnect != "")
1089 Operation[connectPosition]->SetConnectRestore(newTaskName);
1090 checkCurrentItem(ui.listWidget_operations -> currentItem());
1091
1092 // update all relevant snap .changes as well as log files if the task name changes
1093 if (newTaskName != oldTaskName)
1094 arrangeLogSnap(0,"rename",oldTaskName);
1095
1096 if (saveOrNot) // also save the current profile if saveOrNot is true
1097 saveCurrentProfile();
1098 }
1099 }
1100
1101 // remove ===========================================================================================================================================
1102 // Removes highlighted operation from available list
remove()1103 void luckyBackupWindow::remove()
1104 {
1105 currentOperation = ui.listWidget_operations -> currentRow(); //current Included list row number
1106 if (currentOperation < 0) //if nothing is selected do nothing
1107 {
1108 InfoData = tr("Please select a task to remove first") + " !!";
1109 ui.textBrowser_info -> setText(InfoData);
1110 return;
1111 }
1112
1113 QString tempConnect = Operation[currentOperation] -> GetConnectRestore();
1114 QString oldTaskName = Operation[currentOperation] -> GetName(); // the original task name wil become handy in case it changes
1115
1116 textDialog textdialogQ ("QtQuestion", tr("Are you sure you want to remove the following task ??")+" <br>" +
1117 (ui.listWidget_operations -> currentItem()) -> text(), this);
1118 textdialogQ.exec();
1119
1120 if (textdialogQ.getGoOn() > 0) //if user answers yes
1121 {
1122 textDialog textdialogQ2 ("QtQuestion", tr("Would you like to also remove:")+" <br>" + tempConnect+"<br>??", this);
1123 if (tempConnect != "") //if this op is already connected with another op ask to remove that too
1124 textdialogQ2.exec();
1125
1126 //remove current operation
1127 ui.listWidget_operations -> takeItem(currentOperation); //take out the selected item from the list
1128 TotalOperations = ui.listWidget_operations -> count(); //TotalOperations takes the new value (old - 1)
1129 while (currentOperation < TotalOperations) //shift array "Operation" one position up starting at current row
1130 {
1131 Operation[currentOperation]=Operation[currentOperation+1]; //make the current array item the same with the next one
1132 currentOperation ++;
1133 }
1134
1135 if (tempConnect != "")
1136 {
1137 currentOperation=0;
1138 while (currentOperation < TotalOperations)
1139 { if (Operation[currentOperation]->GetName()==tempConnect)
1140 {
1141 if (textdialogQ2.getGoOn() > 0) //remove current (conected) operation
1142 {
1143 ui.listWidget_operations -> takeItem(currentOperation);
1144 TotalOperations = ui.listWidget_operations -> count();
1145 while (currentOperation < TotalOperations)
1146 {
1147 Operation[currentOperation]=Operation[currentOperation+1];
1148 currentOperation ++;
1149 }
1150 }
1151 else //just remove the connection
1152 Operation[currentOperation]->SetConnectRestore("");
1153 break;
1154 }
1155 currentOperation ++;
1156 }
1157 }
1158 savedProfile = false; //change profile status to "unsaved"
1159 ui.actionSave -> setEnabled(true);
1160
1161 // add the deleted yask name to this list to be used when profile is saved
1162 deletedTaskNames << oldTaskName;
1163 }
1164 }
1165
1166 // manage ==========================================================================================================================================
1167 // Manage existing backups of an existing operation by calling the manageDialog
manage()1168 void luckyBackupWindow::manage()
1169 {
1170 currentOperation = ui.listWidget_operations -> currentRow(); //current Included list row number
1171 if (currentOperation < 0) //if nothing is selected do nothing
1172 {
1173 InfoData = tr("Please select a task to manage first") + " !!";
1174 ui.textBrowser_info -> setText(InfoData);
1175 return;
1176 }
1177
1178 manageDialog managedialog;
1179 managedialog.exec();
1180
1181 checkCurrentItem(ui.listWidget_operations -> currentItem()); //refresh the selected task
1182 saveCurrentProfile(); // save the profile if any snapshots have been deleted
1183 // refreshList(); //refresh the listWidget_operations
1184 }
1185
1186 // moveUp ===========================================================================================================================================
1187 // Moves highlighted operation one position up in the available list
moveUp()1188 void luckyBackupWindow::moveUp()
1189 {
1190 currentOperation = ui.listWidget_operations -> currentRow(); //current list row number
1191 TotalOperations = ui.listWidget_operations -> count(); //total number of list items
1192 if ( currentOperation < 0 ) //if nothing is selected
1193 return;
1194
1195 if ( currentOperation > 0 )
1196 {
1197 operation *tempOp; //temp operation to use for swaping
1198 tempOp = Operation[currentOperation]; //swap array items
1199 Operation[currentOperation] = Operation [currentOperation-1];
1200 Operation[currentOperation-1] = tempOp;
1201
1202 QListWidgetItem * currentItem = ui.listWidget_operations -> takeItem(currentOperation); //swap list items
1203 ui.listWidget_operations -> insertItem(currentOperation - 1, currentItem);
1204 ui.listWidget_operations -> setCurrentRow(currentOperation - 1);
1205
1206 savedProfile = false; //change profile status to "unsaved"
1207 ui.actionSave -> setEnabled(true);
1208 }
1209 }
1210
1211 // moveDown =========================================================================================================================================
1212 // Moves highlighted operation one position down in the available list
moveDown()1213 void luckyBackupWindow::moveDown()
1214 {
1215 currentOperation = ui.listWidget_operations -> currentRow(); //current list row number
1216 TotalOperations = ui.listWidget_operations -> count(); //total number of list items
1217 if ( currentOperation < 0 ) //if nothing is selected
1218 return;
1219
1220 if (currentOperation < (TotalOperations-1))
1221 {
1222 operation *tempOp; //temp operation to use for swaping
1223 tempOp = Operation[currentOperation]; //swap array
1224 Operation[currentOperation] = Operation [currentOperation+1];
1225 Operation[currentOperation+1] = tempOp;
1226
1227 QListWidgetItem * currentItem = ui.listWidget_operations -> takeItem(currentOperation); //swap list items
1228 ui.listWidget_operations -> insertItem(currentOperation + 1, currentItem);
1229 ui.listWidget_operations -> setCurrentRow(currentOperation + 1);
1230
1231 savedProfile = false; //change profile status to "unsaved"
1232 ui.actionSave -> setEnabled(true);
1233 }
1234 }
1235
1236
1237 // start ============================================================================================================================================
1238 //start the execution of operations
start()1239 void luckyBackupWindow::start()
1240 {
1241 TotalOperations = ui.listWidget_operations -> count(); //set TotalOperations to what it is now
1242
1243 if (!checkOperationList()) //check the Operations list for "errors" (eg nothing is included or the list is empty)
1244 return;
1245
1246 checkDeclared(); //Check if the declared data are ok by calling checkBackupDirs, checkSyncDirs accordingly
1247
1248 if (NothingToDo == true) //if there is nothing to Do anyway then just display a message
1249 {
1250 InfoData = "<font color=red><b>" + tr("ERROR") + "</b></font><br>" +
1251 "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br><b>" +
1252 tr("You have only included tasks that are going to be skipped") + "</b><br>" +
1253 "..." + tr("nothing to do") +" !!";
1254
1255 ui.textBrowser_info -> setText(InfoData);
1256 return;
1257 }
1258
1259 DryRun = ui.checkBox_DryRun -> isChecked(); //set bool Dryrun according to checkbox
1260
1261 executeNOW();
1262 }
1263
1264 // schedule==========================================================================================================================================
1265 // Displays a new dialog to make a cron job for included operations
schedule()1266 void luckyBackupWindow::schedule()
1267 {
1268 scheduleDialog scheduledialog;
1269 scheduledialog.exec();
1270
1271 if (crontabUpdated)
1272 InfoData = tr("current crontab <font color=green>updated successfully") + "</font>";
1273 ui.textBrowser_info -> setText(InfoData);
1274
1275 crontabUpdated = false; //this is set true each time the crontab is update
1276 }
1277
1278 // email==========================================================================================================================================
1279 // Displays a new dialog to email report after a profile execution
email()1280 void luckyBackupWindow::email()
1281 {
1282 emailDialog emaildialog;
1283 emaildialog.exec();
1284
1285 if (emaildialog.getGoOn() == 0) // everything went ok
1286 {
1287 InfoData = tr("Email preferences have been <font color=green>updated successfully") + "</font>";
1288 ui.textBrowser_info -> setText(InfoData);
1289
1290 savedProfile = false; //change profile status to "unsaved"
1291 ui.actionSave -> setEnabled(true);
1292 }
1293
1294 }
1295
1296 // taskStateChanged =================================================================================================================================
1297 // Sets the profile state to unsaved if a task checkbox is changed
taskStateChanged()1298 void luckyBackupWindow::taskStateChanged()
1299 {
1300 //theory (due to connections at luckybackwindow constructor):
1301 //when an item is just clicked functions called: checkCurrentItem -> taskStateChanged
1302 //when a checkbox state changes functiond called: taskStateChanged -> checkCurrentItem -> taskStateChanged
1303 //when a checkbox state changes not by clicking but with SPACEBAR, only taskStateChanged is called !!
1304
1305 if (!taskChanged)
1306 {
1307 if (taskClicked)
1308 taskClicked = false;
1309 else
1310 taskChanged = true;
1311 return;
1312 }
1313
1314 if ( (taskChanged) && (taskClicked) )
1315 {
1316 savedProfile = false; //change profile status to "unsaved"
1317 ui.actionSave -> setEnabled(true);
1318 }
1319
1320 taskClicked = false;
1321 taskChanged = false;
1322 }
1323
1324 // checkCurrentItem =================================================================================================================================
1325 // Checks the currently selected operation (if checked) for validity
checkCurrentItem(QListWidgetItem * thisIsTheCurrentItem)1326 void luckyBackupWindow::checkCurrentItem(QListWidgetItem *thisIsTheCurrentItem)
1327 {
1328 taskClicked = true; //this is used at taskStateChanged() to determine if a task state is changed
1329
1330 InfoData="";
1331 CheckedData = "";
1332
1333 // use this because when a checkbox state changes and another item is selected, it remains this way. The checked one does not become selected !!
1334 ui.listWidget_operations -> setCurrentItem(thisIsTheCurrentItem);
1335 currentOperation = ui.listWidget_operations -> currentRow();
1336
1337 if (currentOperation < 0) // to avoid segfault when nothing selected
1338 return;
1339
1340 //first set variables source & dest
1341 QString source, dest;
1342 source = Operation[currentOperation] -> GetSource();
1343 dest = Operation[currentOperation] -> GetDestination();
1344
1345 if (Operation[currentOperation] -> GetTypeSync()) //if the operation is of type "sync dirs'
1346 {
1347 ui.action_TaskCreateRestore -> setEnabled(false); //grey out the "create restore task" from menu
1348 ui.action_TaskManageBackup -> setText(tr("Manage Task","This is a top 'Task' menu action"));
1349 ui.action_TaskManageBackup -> setToolTip(tr("display information regarding highlighted task",
1350 "This is a top 'Task' menu action tooltip"));
1351 }
1352 else
1353 {
1354 ui.action_TaskCreateRestore -> setEnabled(true);
1355 ui.action_TaskManageBackup -> setText(tr("Manage &Backup","This is a top 'Task' menu action"));
1356 ui.action_TaskManageBackup -> setToolTip(tr("display - restore - delete existing backups of highlighted task",
1357 "This is a top 'Task' menu action tooltip"));
1358 }
1359
1360 if (ui.listWidget_operations -> currentItem() -> checkState() == Qt::Unchecked) //if the operation is " NOT included" do not check it
1361 {
1362 ui.listWidget_operations -> currentItem() -> setIcon(QIcon(":/luckyPrefix/about.png"));
1363 CheckedData.append(tr("status") + ": <font color=blue><b>"+tr("NOT INCLUDED")+"</font></b><br>");
1364 CheckedData.append(tr("Checks are disabled. This task will be <b>skipped</b>"));
1365 ui.textBrowser_info -> setText(CheckedData);
1366 Operation[currentOperation] -> SetIncluded(false); // also set its include state to false
1367 return;
1368 }
1369
1370 Operation[currentOperation] -> SetIncluded(true); // also set its include state to true
1371
1372 if ( (Operation[currentOperation] -> GetTypeDirContents()) || (Operation[currentOperation] -> GetTypeDirName()) )
1373 checkBackupDirs(source,dest); //if the operation is of type "backup dir ...'
1374 if (Operation[currentOperation] -> GetTypeSync()) //if the operation is of type "sync dirs'
1375 checkSyncDirs(source,dest);
1376
1377 if (Operation[currentOperation] -> GetOK())
1378 ui.listWidget_operations -> currentItem() -> setIcon(QIcon(":/luckyPrefix/okay.png"));
1379 if (Operation[currentOperation] -> GetWARNING())
1380 ui.listWidget_operations -> currentItem() -> setIcon(QIcon(":/luckyPrefix/cancel.png"));
1381 if (Operation[currentOperation] -> GetCRITICAL())
1382 ui.listWidget_operations -> currentItem() -> setIcon(QIcon(":/luckyPrefix/warning.png"));
1383 if (Operation[currentOperation] -> GetSourcePerms())
1384 ui.listWidget_operations -> currentItem() -> setIcon(QIcon(":/luckyPrefix/cancel.png"));
1385 if (Operation[currentOperation] -> GetDestPerms())
1386 ui.listWidget_operations -> currentItem() -> setIcon(QIcon(":/luckyPrefix/cancel.png"));
1387 ui.textBrowser_info -> setText(CheckedData);
1388 }
1389
1390 // refreshList ======================================================================================================================================
1391 // refreshes the task list and the profile combobox when button refresh clicked
refreshList()1392 void luckyBackupWindow::refreshList()
1393 {
1394 TotalOperations = ui.listWidget_operations -> count(); //Get the Operations list size
1395 checkDeclared(); // Check tasks & set icons
1396 createProfileCombo(); // update the profile combobox with all existing profiles and set index to currentProfile
1397 InfoData = tr("Task list of profile","full phrase: 'Task list of profile <PROFILENAME> and 'profile' drop-down list refreshed'") +
1398 " <b>" + profileName + "</b><br>" +
1399 tr("and 'profile' drop-down list","full phrase: 'Task list of profile <PROFILENAME> and 'profile' drop-down list refreshed'") +
1400 "<br>...<font color=blue>" + tr("refreshed",
1401 "full phrase: 'Task list of profile <PROFILENAME> and 'profile' drop-down list refreshed'") + " !!</font>";
1402 ui.textBrowser_info -> setText(InfoData);
1403 }
1404
1405 //===================================================================================================================================================
1406 //end of luckybackupwindow.cpp
1407