3
3
import os .path
4
4
import re
5
5
import shlex
6
+ import subprocess
6
7
import sys
8
+ import textwrap
7
9
import tkinter as tk
8
10
import tkinter .filedialog
9
11
import tkinter .ttk as ttk
10
12
import winreg
11
13
import argparse
14
+
12
15
from WinJobster import Process
13
16
import jsons
14
17
@@ -68,7 +71,9 @@ def load(self):
68
71
with open (self .filename , 'r' , encoding = 'utf-8-sig' ) as file :
69
72
self .config = jsons .loads (file .read (), Config )
70
73
except OSError :
71
- pass
74
+ self .save ()
75
+ except jsons .DeserializationError :
76
+ self .save ()
72
77
73
78
def save (self ):
74
79
with open (self .filename , 'w' , encoding = 'utf-8-sig' ) as file :
@@ -164,6 +169,10 @@ def save_settings(self):
164
169
self ._config_storage .save ()
165
170
166
171
172
+ def open_path (path ):
173
+ os .system (f'explorer /select,"{ os .path .normpath (path )} "' )
174
+
175
+
167
176
class AppView (ttk .Frame ):
168
177
def __init__ (self , parent , app : ProcessModel ,
169
178
toggle_callback , delete_callback ):
@@ -183,7 +192,7 @@ def __init__(self, parent, app: ProcessModel,
183
192
).pack (side = tk .LEFT , padx = 4 , pady = 8 )
184
193
self .open_folder_btn = ttk .Button (
185
194
master = self , text = "Open folder" ,
186
- command = lambda : self . open_app_path (self .app .path )
195
+ command = lambda : open_path (self .app .path )
187
196
)
188
197
self .open_folder_btn .pack (side = tk .LEFT , padx = 4 , pady = 8 )
189
198
self .set_app (app )
@@ -207,8 +216,23 @@ def get_state(app: ProcessModel):
207
216
return "ACTIVE"
208
217
return "NOT ACTIVE"
209
218
210
- def open_app_path (self , path ):
211
- os .system (f'explorer /select,"{ os .path .normpath (path )} "' )
219
+
220
+ def make_shortcut (app_path : str , args : str , shortcut_path : str ):
221
+ workdir = os .path .dirname (app_path )
222
+ command = textwrap .dedent (f"""
223
+ Set objWS = WScript.CreateObject("WScript.Shell")
224
+ Set objLink = objWS.CreateShortcut("{ shortcut_path } ")
225
+
226
+ objLink.TargetPath = "{ app_path } "
227
+ objLink.Arguments = "{ args } "
228
+ objLink.IconLocation = "{ app_path } "
229
+ objLink.WorkingDirectory = "{ workdir } "
230
+ objLink.Save
231
+ """ ).strip ()
232
+ with open ("make_shortcut.vbs" , 'w' ) as f :
233
+ f .write (command )
234
+ os .system ("CSCRIPT .\\ make_shortcut.vbs" )
235
+ os .remove (".\\ make_shortcut.vbs" )
212
236
213
237
214
238
class View (ttk .Frame ):
@@ -238,6 +262,8 @@ def __init__(self, parent):
238
262
variable = self .run_at_startup , command = lambda : self .controller .set_run_at_startup (bool (self .run_at_startup .get ()))).pack (anchor = "w" )
239
263
ttk .Checkbutton (master = bottom_bar , text = "Kill all apps when program closed" ,
240
264
variable = self .kill_on_close , command = lambda : self .controller .set_kill_on_close (bool (self .kill_on_close .get ()))).pack (anchor = "w" )
265
+ ttk .Button (master = bottom_bar , text = "Make new config" , command = self .make_new_config_callback )\
266
+ .pack (anchor = "w" , pady = 8 )
241
267
self ._apps_stored = []
242
268
self ._apps_views = []
243
269
self .refresh ()
@@ -292,6 +318,33 @@ def get_apps_paths(self) -> tuple[str]:
292
318
filetypes = (("Executable" , ".exe .bat .cmd .url .lnk" ), ("Other" , "*.*" ))
293
319
) or tuple ()
294
320
321
+ def make_new_config_callback (self ):
322
+ new_config = self .get_new_config_path ()
323
+ if not new_config :
324
+ return
325
+ new_config = os .path .normpath (new_config )
326
+ config_dir = os .path .dirname (new_config )
327
+ app_name = os .path .basename (sys .argv [0 ]).split ("." )[0 ]
328
+ config_name = os .path .basename (new_config ).split ("." )[0 ]
329
+ config_storage = ConfigStorage (new_config )
330
+ config_storage .config .rules_path = os .path .join (config_dir , config_storage .config .rules_path )
331
+ config_storage .save ()
332
+ link_path = os .path .join (config_dir , f"New { app_name } for { config_name } .lnk" )
333
+ make_shortcut (
334
+ sys .argv [0 ],
335
+ f'-c ""{ new_config } ""' ,
336
+ link_path
337
+ )
338
+ open_path (link_path )
339
+
340
+ def get_new_config_path (self ) -> str :
341
+ return tk .filedialog .asksaveasfilename (
342
+ defaultextension = "json" ,
343
+ initialfile = "config" ,
344
+ filetypes = (("json" , ".json" ,),),
345
+ title = 'Save new config to' ,
346
+ ) or None
347
+
295
348
def delete_app_callback (self , app ):
296
349
self .controller .delete_app (app )
297
350
@@ -350,11 +403,12 @@ def set_kill_on_close(self, value: bool):
350
403
self .model .save_settings ()
351
404
352
405
406
+
353
407
class App (tk .Tk ):
354
408
def __init__ (self , args ):
355
409
super ().__init__ ()
356
410
self .title ('Apps bulk start/stop' )
357
- self .geometry ('640x480 ' )
411
+ self .geometry ('640x520 ' )
358
412
self .apply_theme ()
359
413
model = Model (args )
360
414
view = View (self )
0 commit comments