Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

289 řádky
9.1 KiB

před 15 roky
před 15 roky
před 15 roky
před 15 roky
před 15 roky
před 15 roky
před 15 roky
před 15 roky
před 15 roky
před 15 roky
před 15 roky
před 15 roky
před 15 roky
  1. #!/usr/bin/env python2
  2. import subprocess
  3. import cPickle
  4. import os.path
  5. import os
  6. import sys
  7. import pygtk
  8. pygtk.require('2.0')
  9. import gtk
  10. from autojump import open_dic,get_dic_file
  11. defaults={}
  12. actions={}
  13. #directory finding helpers, conforming to the XDG Base Directory Specification
  14. def data_dir():
  15. xdg_data_dir = os.environ.get('XDG_DATA_HOME') or os.path.join(os.environ['HOME'], '.local', 'share')
  16. return os.path.join(xdg_data_dir, 'autojump')
  17. def config_dir():
  18. xdg_config_dir = os.environ.get('XDG_CONFIG_HOME') or os.path.join(os.environ['HOME'], '.config')
  19. return os.path.join(xdg_config_dir, 'autojump')
  20. #decorator truff
  21. def action(validator,name=None):
  22. if name is None:
  23. def wrapper(action):
  24. actions[action.__name__]=(action,validator)
  25. else:
  26. def wrapper(action):
  27. actions[name]=(action,validator)
  28. return wrapper
  29. #validator helper
  30. def has_child_dir(dirname,recursion=0):
  31. def wrapper(path):
  32. k=recursion
  33. ii=""
  34. while k>=0:
  35. if os.path.isdir(os.path.join(path,ii,dirname)): return True
  36. k-=1
  37. ii=os.path.join("..",ii)
  38. return False
  39. return wrapper
  40. def has_child_file(filename):
  41. def wrapper(path):
  42. return os.path.isfile(os.path.join(path,filename))
  43. return wrapper
  44. def load_paths(maxpath=10):
  45. path_dict=open_dic(get_dic_file())
  46. path_dict=path_dict.items()
  47. path_dict.sort(key=lambda x: x[1],reverse=True)
  48. return [path for path,score in path_dict[:maxpath]]
  49. def load_settings_file():
  50. filename = os.path.join(config_dir(), 'jumpapplet_py')
  51. #migration from old location
  52. old_filename = os.path.join(os.environ['HOME'], '.jumpapplet_py')
  53. if not os.path.exists(filename) and os.path.exists(old_filename):
  54. os.rename(old_filename, filename)
  55. print "loading settings"
  56. global defaults
  57. dic_file = filename
  58. try:
  59. aj_file=open(dic_file,'r')
  60. defaults=cPickle.load(aj_file)
  61. aj_file.close()
  62. except IOError:
  63. print "no config file"
  64. pass
  65. if not "terminal" in defaults: defaults["terminal"]="gnome-terminal"
  66. if not "navigator" in defaults: defaults["navigator"]="nautilus"
  67. if not "maxpath" in defaults: defaults["maxpath"]=15
  68. if not "invert" in defaults: defaults["invert"]=False
  69. if not "collapse" in defaults: defaults["collapse"]=True
  70. create_actions()
  71. def save_settings_file(filename=None):
  72. directory = config_dir()
  73. if not filename:
  74. filename = os.path.join(directory, 'jumpapplet_py')
  75. if not os.path.exists(directory):
  76. os.makedirs(directory)
  77. print "saving settings"
  78. dic_file= filename
  79. aj_file=open(dic_file,'w')
  80. cPickle.dump(defaults,aj_file)
  81. aj_file.close()
  82. def get_actions(path):
  83. return [(name,action) for name,(action,validator) in actions.items() if validator(path)]
  84. def popup(sender,button,activation):
  85. paths=load_paths(maxpath=defaults["maxpath"])
  86. if defaults["collapse"]:
  87. def collapse_home(path):
  88. return path.replace(os.path.expanduser('~'),"~")
  89. else:
  90. def collapse_home(path):
  91. return path
  92. menu=gtk.Menu()
  93. if defaults["invert"]:
  94. item=gtk.ImageMenuItem(stock_id=gtk.STOCK_QUIT)
  95. item.connect("activate",quit)
  96. menu.append(item)
  97. item=gtk.ImageMenuItem(stock_id=gtk.STOCK_PREFERENCES)
  98. item.connect("activate",settings)
  99. menu.append(item)
  100. menu.append(gtk.SeparatorMenuItem())
  101. for path in reversed(paths):
  102. actions=get_actions(path)
  103. if not actions: continue
  104. item=gtk.MenuItem(collapse_home(path),use_underline=False)
  105. submenu=gtk.Menu()
  106. item.set_submenu(submenu)
  107. for name,action in actions:
  108. subitem=gtk.MenuItem(name)
  109. subitem.connect("activate",action,path)
  110. submenu.append(subitem)
  111. menu.append(item)
  112. else:
  113. for path in paths:
  114. actions=get_actions(path)
  115. if not actions: continue
  116. item=gtk.MenuItem(collapse_home(path),use_underline=False)
  117. submenu=gtk.Menu()
  118. item.set_submenu(submenu)
  119. for name,action in actions:
  120. subitem=gtk.MenuItem(name)
  121. subitem.connect("activate",action,path)
  122. submenu.append(subitem)
  123. menu.append(item)
  124. menu.append(gtk.SeparatorMenuItem())
  125. item=gtk.ImageMenuItem(stock_id=gtk.STOCK_PREFERENCES)
  126. item.connect("activate",settings)
  127. menu.append(item)
  128. item=gtk.ImageMenuItem(stock_id=gtk.STOCK_QUIT)
  129. item.connect("activate",quit)
  130. menu.append(item)
  131. menu.show_all()
  132. menu.popup(None,None,gtk.status_icon_position_menu,button,activation,sender)
  133. def settings(sender):
  134. window=gtk.Dialog("jump applet preferences",None,gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,(gtk.STOCK_SAVE,gtk.RESPONSE_OK,gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL))
  135. window.set_border_width(3)
  136. window.set_resizable(False)
  137. if os.path.isfile("icon.png"): window.set_icon_from_file("icon.png")
  138. elif os.path.isfile("/usr/share/autojump/icon.png"): window.set_icon_from_file("/usr/share/autojump/icon.png")
  139. vbox=gtk.Table(5,2)
  140. vbox.set_row_spacings(3)
  141. window.get_child().add(vbox)
  142. def add_string_setting(name,label,nsettings):
  143. label=gtk.Label(label+' ')
  144. label.set_alignment(1.,.5)
  145. entry=gtk.Entry()
  146. if name in defaults: entry.set_text(defaults[name])
  147. vbox.attach(label,0,1,nsettings,nsettings+1)
  148. vbox.attach(entry,1,2,nsettings,nsettings+1)
  149. return (name,entry)
  150. def add_integer_setting(name,label,nsettings):
  151. label=gtk.Label(label+' ')
  152. label.set_alignment(1.,.5)
  153. entry=gtk.SpinButton()
  154. entry.set_range(5,35)
  155. entry.set_numeric(True)
  156. entry.set_increments(1,5)
  157. entry.set_snap_to_ticks(True)
  158. if name in defaults: entry.set_value(defaults[name])
  159. vbox.attach(label,0,1,nsettings,nsettings+1)
  160. vbox.attach(entry,1,2,nsettings,nsettings+1)
  161. return (name,entry)
  162. def add_bool_setting(name,label,nsettings):
  163. entry=gtk.CheckButton(label=label,use_underline=False)
  164. if name in defaults: entry.set_active(defaults[name])
  165. vbox.attach(entry,0,2,nsettings,nsettings+1)
  166. return (name,entry)
  167. entries=[]
  168. entries.append(add_string_setting("terminal","Terminal program",0))
  169. entries.append(add_string_setting("navigator","Navigator program",1))
  170. entries.append(add_integer_setting("maxpath","Number of directories",2))
  171. entries.append(add_bool_setting("invert","List directories in reverse order",3))
  172. entries.append(add_bool_setting("collapse","Collapse home directory to ~",4))
  173. window.connect("response",save_settings,entries,window)
  174. window.show_all();
  175. def save_settings(sender,response,entries,window):
  176. window.hide_all()
  177. if response!=gtk.RESPONSE_OK: return
  178. global defaults
  179. for name,entry in entries:
  180. try:
  181. defaults[name]=int(entry.get_text())
  182. except (ValueError,AttributeError):
  183. try:
  184. defaults[name]=entry.get_active()
  185. except AttributeError:
  186. defaults[name]=entry.get_text()
  187. save_settings_file()
  188. create_actions()
  189. def init():
  190. load_settings_file()
  191. if os.path.isfile("icon.png"): icon=gtk.status_icon_new_from_file("icon.png")
  192. elif os.path.isfile("/usr/share/autojump/icon.png"): icon=gtk.status_icon_new_from_file("/usr/share/autojump/icon.png")
  193. else: icon=gtk.status_icon_new_from_icon_name("help")
  194. icon.set_visible(True)
  195. icon.connect("popup-menu",popup)
  196. def quit(sender):
  197. gtk.main_quit()
  198. ######################################################
  199. #insert other actions here using the action decorator#
  200. ######################################################
  201. def create_actions():
  202. global actions
  203. actions={}
  204. @action(has_child_dir(".git",recursion=3))
  205. def gitk(sender,path):
  206. if not os.fork():
  207. os.chdir(path)
  208. subprocess.Popen(['gitk']).wait()
  209. sys.exit()
  210. @action(has_child_file("CMakeCache.txt"),"configure")
  211. def cmake(sender,path):
  212. if not os.fork():
  213. os.chdir(path)
  214. subprocess.Popen(['cmake-gui','.']).wait()
  215. sys.exit()
  216. @action(os.path.isdir)
  217. def terminal(sender,path):
  218. print "launch terminal '%s'" % defaults["terminal"]
  219. if not os.fork():
  220. try:
  221. if defaults["terminal"]=="konsole":
  222. subprocess.Popen([defaults["terminal"],"--workdir=%s"%path]).wait()
  223. else:
  224. os.chdir(path)
  225. subprocess.Popen([defaults["terminal"]]).wait()
  226. except OSError:
  227. pass
  228. sys.exit()
  229. @action(os.path.isdir)
  230. def navigator(sender,path):
  231. print "launch navigator '%s'" % defaults["navigator"]
  232. if not os.fork():
  233. try:
  234. subprocess.Popen([defaults["navigator"],path]).wait()
  235. except OSError:
  236. pass
  237. sys.exit()
  238. if __name__=='__main__':
  239. init()
  240. gtk.main()