| 
									
										
										
										
											2023-06-25 16:34:23 -05:00
										 |  |  | #[Copyright 2023 ITwrx. | 
					
						
							|  |  |  | This file is part of EZ-Bkup. | 
					
						
							|  |  |  | EZ-Bkup is released under the General Public License 3.0. | 
					
						
							|  |  |  | See COPYING or <https://www.gnu.org/licenses/> for details.]# | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import owlkettle | 
					
						
							|  |  |  | import "../models/routine", "../shared" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | viewable RoutineEditor: | 
					
						
							|  |  |  |   ## A form for editing a Routine | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   routine: Routine ## The routine that is being edited | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   # Since Routine is passed by value, we need to notify the parent widget of | 
					
						
							|  |  |  |   # any changes to the routine. The changed callback  | 
					
						
							|  |  |  |   proc changed(routine: Routine) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-01 13:33:28 -05:00
										 |  |  | method view(editor: RoutineEditorState): Widget = | 
					
						
							| 
									
										
										
										
											2023-06-25 16:34:23 -05:00
										 |  |  |   result = gui:     | 
					
						
							|  |  |  |     #must have top level container that everything else is inside of. | 
					
						
							|  |  |  |     Box: | 
					
						
							|  |  |  |       orient = OrientY | 
					
						
							|  |  |  |       margin = 12 | 
					
						
							|  |  |  |       spacing = 12 | 
					
						
							|  |  |  |       Box {.expand: false.}: | 
					
						
							|  |  |  |         orient = OrientX | 
					
						
							|  |  |  |         spacing = 6  | 
					
						
							|  |  |  |         Label {.expand: false.}: | 
					
						
							|  |  |  |           text = "<span weight=\"bold\">Name:</span>" | 
					
						
							|  |  |  |           xAlign = 0 | 
					
						
							|  |  |  |           useMarkup = true             | 
					
						
							|  |  |  |         Entry {.expand: false.}: | 
					
						
							|  |  |  |           text = editor.routine.name | 
					
						
							|  |  |  |           xAlign = 0               | 
					
						
							|  |  |  |           proc changed(text: string) = | 
					
						
							|  |  |  |             editor.routine.name = text                 | 
					
						
							|  |  |  |             # Call the changed callback | 
					
						
							|  |  |  |             if not editor.changed.isNil: | 
					
						
							|  |  |  |               editor.changed.callback(editor.routine) | 
					
						
							|  |  |  |       Box {.expand: false.}: | 
					
						
							|  |  |  |         orient = OrientX | 
					
						
							|  |  |  |         spacing = 6 | 
					
						
							|  |  |  |         Label {.expand: false.}: | 
					
						
							| 
									
										
										
										
											2023-06-29 07:09:23 -05:00
										 |  |  |           text = "<span weight=\"bold\" color=\"#FFF469\">Enabled by default?</span>" | 
					
						
							|  |  |  |           tooltip = "Should this Routine be enabled for inclusion in any Bkup run by default?" | 
					
						
							| 
									
										
										
										
											2023-06-25 16:34:23 -05:00
										 |  |  |           xAlign = 0 | 
					
						
							|  |  |  |           useMarkup = true | 
					
						
							|  |  |  |         Switch {.expand: false.}: | 
					
						
							|  |  |  |           state = editor.routine.selByDef | 
					
						
							|  |  |  |           proc changed(state: bool) = | 
					
						
							|  |  |  |             editor.routine.selByDef = state  | 
					
						
							|  |  |  |             if not editor.changed.isNil: | 
					
						
							|  |  |  |               editor.changed.callback(editor.routine) | 
					
						
							|  |  |  |       Label {.expand: false.}: | 
					
						
							| 
									
										
										
										
											2023-06-26 13:14:13 -05:00
										 |  |  |         text = "<span weight=\"bold\" color=\"#FFF469\">Sources:</span>" | 
					
						
							|  |  |  |         tooltip = "The file(s) or folder(s) you want to backup when this Routine is run." | 
					
						
							| 
									
										
										
										
											2023-06-25 16:34:23 -05:00
										 |  |  |         xAlign = 0 | 
					
						
							|  |  |  |         useMarkup = true | 
					
						
							|  |  |  |       Box {.expand: false.}: | 
					
						
							|  |  |  |         spacing = 6 | 
					
						
							|  |  |  |         Button {.expand: false.}: | 
					
						
							|  |  |  |           text = "+ File" | 
					
						
							|  |  |  |           style = [ButtonSuggested] | 
					
						
							|  |  |  |           proc clicked() = | 
					
						
							|  |  |  |             let (res, state) = editor.app.open: gui: | 
					
						
							|  |  |  |               FileChooserDialog: | 
					
						
							|  |  |  |                 title = "Add Source Files to Routine" | 
					
						
							|  |  |  |                 action = FileChooserOpen  | 
					
						
							|  |  |  |                 selectMultiple = true                  | 
					
						
							|  |  |  |                 DialogButton {.addButton.}: | 
					
						
							|  |  |  |                   text = "Cancel" | 
					
						
							|  |  |  |                   res = DialogCancel                   | 
					
						
							|  |  |  |                 DialogButton {.addButton.}: | 
					
						
							|  |  |  |                   text = "Confirm" | 
					
						
							|  |  |  |                   res = DialogAccept | 
					
						
							|  |  |  |                   style = [ButtonSuggested]               | 
					
						
							|  |  |  |             if res.kind == DialogAccept: | 
					
						
							|  |  |  |               for filename in FileChooserDialogState(state).filenames: | 
					
						
							|  |  |  |                 if hasCommas(filename): | 
					
						
							|  |  |  |                   discard editor.app.open: gui: | 
					
						
							|  |  |  |                     MessageDialog: | 
					
						
							|  |  |  |                       message = "Commas in Source filename/path are not supported." | 
					
						
							|  |  |  |                       style = [StyleClass("error")]                   | 
					
						
							|  |  |  |                       DialogButton {.addButton.}: | 
					
						
							|  |  |  |                         text = "Ok" | 
					
						
							|  |  |  |                         res = DialogAccept | 
					
						
							|  |  |  |                 elif filename in editor.routine.sources: | 
					
						
							|  |  |  |                   discard editor.app.open: gui: | 
					
						
							|  |  |  |                     MessageDialog: | 
					
						
							|  |  |  |                       message = "Duplicate Routine Source filenames (" & filename & ") are not supported." | 
					
						
							|  |  |  |                       style = [StyleClass("error")]                   | 
					
						
							|  |  |  |                       DialogButton {.addButton.}: | 
					
						
							|  |  |  |                         text = "Ok" | 
					
						
							|  |  |  |                         res = DialogAccept | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                   editor.routine.sources.add(filename) | 
					
						
							|  |  |  |                   if not editor.changed.isNil: | 
					
						
							|  |  |  |                     editor.changed.callback(editor.routine)   | 
					
						
							|  |  |  |         Button {.expand: false.}: | 
					
						
							|  |  |  |           text = "+ Folder" | 
					
						
							|  |  |  |           style = [ButtonSuggested] | 
					
						
							|  |  |  |           proc clicked() = | 
					
						
							|  |  |  |             let (res, state) = editor.app.open: gui: | 
					
						
							|  |  |  |               FileChooserDialog: | 
					
						
							|  |  |  |                 title = "Add Source Folders to Routine" | 
					
						
							|  |  |  |                 action = FileChooserSelectFolder   | 
					
						
							|  |  |  |                 selectMultiple = true                | 
					
						
							|  |  |  |                 DialogButton {.addButton.}: | 
					
						
							|  |  |  |                   text = "Cancel" | 
					
						
							|  |  |  |                   res = DialogCancel                   | 
					
						
							|  |  |  |                 DialogButton {.addButton.}: | 
					
						
							|  |  |  |                   text = "Confirm" | 
					
						
							|  |  |  |                   res = DialogAccept | 
					
						
							|  |  |  |                   style = [ButtonSuggested]               | 
					
						
							|  |  |  |             if res.kind == DialogAccept: | 
					
						
							|  |  |  |               for filename in FileChooserDialogState(state).filenames: | 
					
						
							|  |  |  |                 if hasCommas(filename): | 
					
						
							|  |  |  |                   discard editor.app.open: gui: | 
					
						
							|  |  |  |                     MessageDialog: | 
					
						
							|  |  |  |                       message = "Commas in Source filename/path are not supported." | 
					
						
							|  |  |  |                       style = [StyleClass("error")]                   | 
					
						
							|  |  |  |                       DialogButton {.addButton.}: | 
					
						
							|  |  |  |                         text = "Ok" | 
					
						
							|  |  |  |                         res = DialogAccept | 
					
						
							|  |  |  |                 elif filename in editor.routine.sources: | 
					
						
							|  |  |  |                   discard editor.app.open: gui: | 
					
						
							|  |  |  |                     MessageDialog: | 
					
						
							|  |  |  |                       message = "Duplicate Routine Source (" & filename & ") not supported." | 
					
						
							|  |  |  |                       style = [StyleClass("error")]                   | 
					
						
							|  |  |  |                       DialogButton {.addButton.}: | 
					
						
							|  |  |  |                         text = "Ok" | 
					
						
							|  |  |  |                         res = DialogAccept | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                   editor.routine.sources.add(filename)  | 
					
						
							|  |  |  |                   if not editor.changed.isNil: | 
					
						
							|  |  |  |                     editor.changed.callback(editor.routine) | 
					
						
							|  |  |  |       Box {.expand: false.}: | 
					
						
							|  |  |  |         orient = OrientY | 
					
						
							|  |  |  |         margin = 6 | 
					
						
							|  |  |  |         spacing = 6 | 
					
						
							|  |  |  |         #routineSeq returns an empty seq when no sources exist. | 
					
						
							|  |  |  |         if editor.routine.sources.len != 0: | 
					
						
							|  |  |  |           for it, routineSource in editor.routine.sources:       | 
					
						
							|  |  |  |             Box: | 
					
						
							|  |  |  |               orient = OrientX | 
					
						
							|  |  |  |               spacing = 6 | 
					
						
							|  |  |  |               Label: | 
					
						
							|  |  |  |                 text = routineSource | 
					
						
							|  |  |  |                 xAlign = 0              | 
					
						
							|  |  |  |               Button {.expand: false.}: | 
					
						
							| 
									
										
										
										
											2023-06-26 13:14:13 -05:00
										 |  |  |                 icon = "user-trash-symbolic"    | 
					
						
							|  |  |  |                 tooltip = "Delete this Source. Warning: will not ask you to confirm."            | 
					
						
							| 
									
										
										
										
											2023-06-25 16:34:23 -05:00
										 |  |  |                 proc clicked() = | 
					
						
							|  |  |  |                   editor.routine.sources.delete(it) | 
					
						
							|  |  |  |                   if not editor.changed.isNil: | 
					
						
							|  |  |  |                     editor.changed.callback(editor.routine) | 
					
						
							|  |  |  |       Label {.expand: false.}: | 
					
						
							| 
									
										
										
										
											2023-06-26 13:14:13 -05:00
										 |  |  |         text = "<span weight=\"bold\" color=\"#FFF469\">Destinations:</span>" | 
					
						
							|  |  |  |         tooltip = "The folder(s) or drive(s) you want to backup this Routine's Sources to." | 
					
						
							| 
									
										
										
										
											2023-06-25 16:34:23 -05:00
										 |  |  |         xAlign = 0 | 
					
						
							|  |  |  |         useMarkup = true | 
					
						
							|  |  |  |       Box {.expand: false.}: | 
					
						
							|  |  |  |         spacing = 6   | 
					
						
							|  |  |  |         Button {.expand: false.}: | 
					
						
							| 
									
										
										
										
											2023-06-26 12:29:27 -05:00
										 |  |  |           text = "+ Folder/Drive" | 
					
						
							| 
									
										
										
										
											2023-06-25 16:34:23 -05:00
										 |  |  |           style = [ButtonSuggested] | 
					
						
							|  |  |  |           proc clicked() = | 
					
						
							|  |  |  |             let (res, state) = editor.app.open: gui: | 
					
						
							|  |  |  |               FileChooserDialog: | 
					
						
							|  |  |  |                 title = "Add Destination Folders to Routine" | 
					
						
							|  |  |  |                 action = FileChooserSelectFolder  | 
					
						
							|  |  |  |                 selectMultiple = true                  | 
					
						
							|  |  |  |                 DialogButton {.addButton.}: | 
					
						
							|  |  |  |                   text = "Cancel" | 
					
						
							|  |  |  |                   res = DialogCancel                   | 
					
						
							|  |  |  |                 DialogButton {.addButton.}: | 
					
						
							|  |  |  |                   text = "Confirm" | 
					
						
							|  |  |  |                   res = DialogAccept | 
					
						
							|  |  |  |                   style = [ButtonSuggested]  | 
					
						
							|  |  |  |             if res.kind == DialogAccept: | 
					
						
							|  |  |  |               for filename in FileChooserDialogState(state).filenames: | 
					
						
							|  |  |  |                 if hasCommas(filename): | 
					
						
							|  |  |  |                   discard editor.app.open: gui: | 
					
						
							|  |  |  |                     MessageDialog: | 
					
						
							|  |  |  |                       message = "Commas in Destination filename/path are not supported." | 
					
						
							|  |  |  |                       style = [StyleClass("error")]                   | 
					
						
							|  |  |  |                       DialogButton {.addButton.}: | 
					
						
							|  |  |  |                         text = "Ok" | 
					
						
							|  |  |  |                         res = DialogAccept | 
					
						
							|  |  |  |                 elif filename in editor.routine.destinations: | 
					
						
							|  |  |  |                   discard editor.app.open: gui: | 
					
						
							|  |  |  |                     MessageDialog: | 
					
						
							|  |  |  |                       message = "Duplicate Routine Destination (" & filename & ") not supported." | 
					
						
							|  |  |  |                       style = [StyleClass("error")]                   | 
					
						
							|  |  |  |                       DialogButton {.addButton.}: | 
					
						
							|  |  |  |                         text = "Ok" | 
					
						
							|  |  |  |                         res = DialogAccept | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                   editor.routine.destinations.add(filename) | 
					
						
							|  |  |  |                   if not editor.changed.isNil: | 
					
						
							|  |  |  |                     editor.changed.callback(editor.routine) | 
					
						
							|  |  |  |       Box {.expand: false.}: | 
					
						
							|  |  |  |         orient = OrientY | 
					
						
							|  |  |  |         margin = 6 | 
					
						
							|  |  |  |         spacing = 6 | 
					
						
							|  |  |  |         #routineSeq returns an empty seq when no destinations exist. | 
					
						
							|  |  |  |         if editor.routine.destinations.len != 0: | 
					
						
							|  |  |  |           for it, routineDestination in editor.routine.destinations:      | 
					
						
							|  |  |  |             Box: | 
					
						
							|  |  |  |               orient = OrientX | 
					
						
							|  |  |  |               spacing = 6 | 
					
						
							|  |  |  |               Label: | 
					
						
							|  |  |  |                 text = routineDestination | 
					
						
							|  |  |  |                 xAlign = 0              | 
					
						
							|  |  |  |               Button {.expand: false.}: | 
					
						
							| 
									
										
										
										
											2023-06-26 13:14:13 -05:00
										 |  |  |                 icon = "user-trash-symbolic"   | 
					
						
							|  |  |  |                 tooltip = "Delete this Destination. Warning: will not ask you to confirm."             | 
					
						
							| 
									
										
										
										
											2023-06-25 16:34:23 -05:00
										 |  |  |                 proc clicked() = | 
					
						
							|  |  |  |                   editor.routine.destinations.delete(it) | 
					
						
							|  |  |  |                   if not editor.changed.isNil: | 
					
						
							|  |  |  |                     editor.changed.callback(editor.routine)         | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export RoutineEditor |