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