/ftpedit/ftpedit/ftpwindow.py

http://editra-plugins.googlecode.com/ · Python · 694 lines · 607 code · 30 blank · 57 comment · 6 complexity · d221c90d9f7e9210c37b2fe9d6999f99 MD5 · raw file

  1. ###############################################################################
  2. # Name: ftpwindow.py #
  3. # Purpose: Ftp Window #
  4. # Author: Cody Precord <cprecord@editra.org> #
  5. # Copyright: (c) 2008 Cody Precord <staff@editra.org> #
  6. # License: wxWindows License #
  7. ###############################################################################
  8. """Ftp Window"""
  9. __author__ = "Cody Precord <cprecord@editra.org>"
  10. __svnid__ = "$Id: ftpwindow.py 1223 2011-04-06 15:20:53Z CodyPrecord $"
  11. __revision__ = "$Revision: 1223 $"
  12. #-----------------------------------------------------------------------------#
  13. # Imports
  14. import os
  15. import wx
  16. import wx.lib.mixins.listctrl as listmix
  17. # Editra Libraries
  18. import ed_glob
  19. import ed_msg
  20. from profiler import Profile_Get, Profile_Set
  21. import util
  22. import eclib
  23. import ed_basewin
  24. # Local Imports
  25. import IconFile
  26. import ftpconfig
  27. import ftpclient
  28. import ftpfile
  29. #-----------------------------------------------------------------------------#
  30. # Globals
  31. CONFIG_KEY = u"FtpEdit.Sites"
  32. ID_SITES = wx.NewId()
  33. # Context Menu
  34. ID_REFRESH = wx.NewId()
  35. ID_EDIT = wx.NewId()
  36. ID_RENAME = wx.NewId()
  37. ID_DELETE = wx.NewId()
  38. ID_NEW_FILE = wx.NewId()
  39. ID_NEW_FOLDER = wx.NewId()
  40. ID_COPY_URL = wx.NewId()
  41. ID_DOWNLOAD = wx.NewId()
  42. ID_UPLOAD = wx.NewId()
  43. MENU_IDS = [ ID_REFRESH, ID_EDIT, ID_RENAME, ID_DELETE, ID_NEW_FILE,
  44. ID_NEW_FOLDER, ID_COPY_URL, ID_DOWNLOAD, ID_UPLOAD ]
  45. _ = wx.GetTranslation
  46. #-----------------------------------------------------------------------------#
  47. class FtpWindow(ed_basewin.EdBaseCtrlBox):
  48. """Ftp file window"""
  49. def __init__(self, parent, id_=wx.ID_ANY):
  50. super(FtpWindow, self).__init__(parent, id_)
  51. # Attributes
  52. self._mw = ed_basewin.FindMainWindow(self)
  53. self._config = ftpconfig.ConfigData
  54. self._config.SetData(Profile_Get(CONFIG_KEY, default=dict()))
  55. self._connected = False
  56. self._client = ftpclient.FtpClient(self)
  57. self._files = list()
  58. self._select = None
  59. self._open = list() # Open ftpfile objects
  60. # Ui controls
  61. self._cbar = None # ControlBar
  62. self._list = None # FtpList
  63. self._sites = None # wx.Choice
  64. self.prefbtn = None
  65. self._username = None # wx.TextCtrl
  66. self._password = None # wx.TextCtrl
  67. # Layout
  68. self.__DoLayout()
  69. self.EnableControls(bool(self._config.GetCount()))
  70. self.RefreshControlBar()
  71. # Event Handlers
  72. self.Bind(wx.EVT_BUTTON, self.OnButton, self.prefbtn)
  73. self.Bind(wx.EVT_BUTTON, self.OnButton, self.cbtn)
  74. self.Bind(wx.EVT_CHOICE, self.OnChoice, id=ID_SITES)
  75. self.Bind(wx.EVT_MENU, self.OnMenu)
  76. self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
  77. self.Bind(ftpclient.EVT_FTP_REFRESH, self.OnRefresh)
  78. self.Bind(ftpclient.EVT_FTP_DOWNLOAD, self.OnDownload)
  79. self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy, self)
  80. # Editra Message Handlers
  81. ed_msg.Subscribe(self.OnThemeChanged, ed_msg.EDMSG_THEME_CHANGED)
  82. ed_msg.Subscribe(self.OnCfgUpdated, ftpconfig.EDMSG_FTPCFG_UPDATED)
  83. def OnDestroy(self, event):
  84. """Cleanup"""
  85. if self:
  86. ed_msg.Unsubscribe(self.OnThemeChanged)
  87. ed_msg.Unsubscribe(self.OnCfgUpdated)
  88. # Cleanup file notifiers
  89. # self.__DisconnectFiles()
  90. def __DisconnectFiles(self):
  91. """Disconnect opened files"""
  92. for fobj in self._open:
  93. try:
  94. fobj[1].ClearFtpStatus()
  95. except:
  96. pass
  97. def __DoLayout(self):
  98. """Layout the window"""
  99. self._cbar = self.CreateControlBar(wx.TOP)
  100. # Preferences
  101. self.prefbtn = self.AddPlateButton(u"", ed_glob.ID_PREF, wx.ALIGN_LEFT)
  102. btn.SetToolTipString(_("Configuration"))
  103. # Sites
  104. self._cbar.AddControl(wx.StaticText(self._cbar, label=_("Sites:")), wx.ALIGN_LEFT)
  105. self._sites = wx.Choice(self._cbar, ID_SITES)
  106. self._cbar.AddControl(self._sites, wx.ALIGN_LEFT)
  107. # Username
  108. self._cbar.AddControl(wx.StaticText(self._cbar, label=_("Username:")), wx.ALIGN_LEFT)
  109. self._username = wx.TextCtrl(self._cbar)
  110. self._cbar.AddControl(self._username, wx.ALIGN_LEFT)
  111. # Password
  112. self._cbar.AddControl(wx.StaticText(self._cbar, label=_("Password:")), wx.ALIGN_LEFT)
  113. self._password = wx.TextCtrl(self._cbar, style=wx.TE_PASSWORD)
  114. self._cbar.AddControl(self._password, wx.ALIGN_LEFT)
  115. # Connect
  116. self._cbar.AddStretchSpacer()
  117. bmp = IconFile.Connect.GetBitmap()
  118. self.cbtn = self.AddPlateButton(_("Connect"), bmp, wx.ALIGN_RIGHT)
  119. # Setup Window
  120. self._list = FtpList(self, wx.ID_ANY)
  121. self.SetWindow(self._list)
  122. def _HandleDisconnect(self):
  123. """Handle having to disconnect from the server"""
  124. self._connected = False
  125. self.cbtn.SetLabel(_("Connect"))
  126. self.cbtn.SetBitmap(IconFile.Connect.GetBitmap())
  127. self._list.DeleteAllItems()
  128. # self.__DisconnectFiles()
  129. self.EnableOptions(True)
  130. # Need to create a new client
  131. tmp = self._client.Clone()
  132. del self._client
  133. self._client = tmp
  134. def _StartBusy(self, busy=True):
  135. """Start/Stop the main windows busy indicator
  136. @keyword busy: bool
  137. """
  138. pid = self._mw.GetId()
  139. if busy:
  140. # Pulse
  141. ed_msg.PostMessage(ed_msg.EDMSG_PROGRESS_SHOW, (pid, True))
  142. ed_msg.PostMessage(ed_msg.EDMSG_PROGRESS_STATE, (pid, -1, -1))
  143. else:
  144. ed_msg.PostMessage(ed_msg.EDMSG_PROGRESS_STATE, (pid, 0, 0))
  145. self._list.Enable(not busy)
  146. def EnableControls(self, enable=True):
  147. """Enable or disable controls in the control bar
  148. @keyword enable: bool
  149. """
  150. for child in self._cbar.GetChildren():
  151. if child.GetId() != wx.ID_PREFERENCES:
  152. child.Enable(enable)
  153. def EnableOptions(self, enable=True):
  154. """Enable or disable the options controls while connecting/disconnecting
  155. from the server.
  156. @param enable: bool
  157. """
  158. for child in self._cbar.GetChildren():
  159. if child is not self.cbtn:
  160. child.Enable(enable)
  161. def NotifyFtpFileDeleted(self, name):
  162. """Callback from FtpFile's owned by this client.
  163. @param name: name of file deleted
  164. """
  165. # Remove the file object from our watch
  166. for idx, finfo in enumerate(list(self._open)):
  167. if finfo[0] == name:
  168. self._open.pop(idx)
  169. break
  170. def OnButton(self, evt):
  171. """Handle Button click events"""
  172. e_id = evt.GetId()
  173. e_obj = evt.GetEventObject()
  174. if e_obj is self.cbtn:
  175. if self._connected:
  176. # Warn if any ftp files are open
  177. # num = len(self._open)
  178. # if num:
  179. # # TODO: use custom dialog with list of files in it
  180. # result = wx.MessageBox(_("There are currently %d ftp files open.\n"
  181. # "If you disconnect now you will be unable to upload any further changes to these files.\n"
  182. # "Disconnect from site?") % num,
  183. # _("Disconnect from Site?"),
  184. # style=wx.YES_NO|wx.CENTER|wx.ICON_WARNING)
  185. # if result == wx.NO:
  186. # return
  187. # Disconnect from server
  188. result = self._client.Disconnect()
  189. if not result:
  190. err = self._client.GetLastError()
  191. wx.MessageBox(_("Error on disconnect:\nError:\n%s") % err,
  192. _("Ftp Error"),
  193. style=wx.OK|wx.CENTER|wx.ICON_ERROR)
  194. self._client.ClearLastError()
  195. self._HandleDisconnect()
  196. else:
  197. # Connect to site
  198. user = self._username.GetValue().strip()
  199. password = self._password.GetValue().strip()
  200. site = self._sites.GetStringSelection()
  201. url = self._config.GetSiteHostname(site)
  202. port = self._config.GetSitePort(site)
  203. self._client.SetDefaultPath(self._config.GetSitePath(site))
  204. self._client.SetHostname(url)
  205. self._client.SetPort(port)
  206. connected = self._client.Connect(user, password)
  207. if not connected:
  208. wx.MessageBox(unicode(self._client.GetLastError()),
  209. _("Ftp Connection Error"),
  210. style=wx.OK|wx.CENTER|wx.ICON_ERROR)
  211. self._client.ClearLastError()
  212. else:
  213. self._connected = True
  214. self.cbtn.SetLabel(_("Disconnect"))
  215. self.cbtn.SetBitmap(IconFile.Disconnect.GetBitmap())
  216. self.RefreshFiles()
  217. self.EnableOptions(False)
  218. self._cbar.Layout()
  219. elif e_id == wx.ID_PREFERENCES:
  220. # Show preferences dialog
  221. app = wx.GetApp()
  222. win = app.GetWindowInstance(ftpconfig.FtpConfigDialog)
  223. if win is None:
  224. config = ftpconfig.FtpConfigDialog(self._mw,
  225. _("Ftp Configuration"))
  226. config.CentreOnParent()
  227. config.Show()
  228. else:
  229. win.Raise()
  230. else:
  231. evt.Skip()
  232. def OnChoice(self, evt):
  233. """Handle Choice Control Events"""
  234. if evt.GetId() == ID_SITES:
  235. # Change the current Site
  236. site = self._sites.GetStringSelection()
  237. password = self._config.GetSitePassword(site)
  238. user = self._config.GetSiteUsername(site)
  239. self._username.SetValue(user)
  240. self._password.SetValue(password)
  241. else:
  242. evt.Skip()
  243. def OnCfgUpdated(self, msg):
  244. """Update state of control bar when configuration data is updated
  245. @param msg: ftpconfig.EDMSG_FTPCFG_UPDATED
  246. """
  247. # Refresh persistent state
  248. Profile_Set(CONFIG_KEY, ftpconfig.ConfigData.GetData())
  249. # Update view for new data
  250. # XXX: got an odd assertion error about an incorrect dc once
  251. # not sure how it could happen other then if the windows was
  252. # being deleted when this was called.
  253. if not self.IsBeingDeleted():
  254. try:
  255. self.RefreshControlBar()
  256. except wx.PyAssertionError:
  257. pass
  258. def OnDownload(self, evt):
  259. """File download has completed
  260. @param evt: ftpclient.EVT_FTP_DOWNLOAD
  261. """
  262. ftppath, path = evt.GetValue()
  263. self._StartBusy(False)
  264. if path is None or not os.path.exists(path):
  265. err = self._client.GetLastError()
  266. if err is not None:
  267. err = unicode(err)
  268. else:
  269. err = _("Unknown")
  270. wx.MessageBox(_("Failed to download %(file)s\nError:\n%(err)s") % \
  271. dict(file=ftppath, err=err),
  272. _("Ftp Download Failed"),
  273. style=wx.OK|wx.CENTER|wx.ICON_ERROR)
  274. self._client.ClearLastError()
  275. else:
  276. # Open the downloaded file in the editor
  277. csel = self._sites.GetStringSelection()
  278. data = self._config.GetSiteData(csel)
  279. data['user'] = self._username.GetValue().strip()
  280. data['pword'] = self._password.GetValue().strip()
  281. nb = self._mw.GetNotebook()
  282. fobj = ftpfile.FtpFile(self._client, ftppath, data, path)
  283. nb.OpenFileObject(fobj)
  284. self._open.append((path, fobj))
  285. fobj.SetDisconnectNotifier(self.NotifyFtpFileDeleted)
  286. def OnItemActivated(self, evt):
  287. """Handle when items are activated in the list control
  288. @param evt: wx.EVT_LIST_ITEM_ACTIVATED
  289. """
  290. idx = evt.GetIndex()
  291. if idx < len(self._files):
  292. item = self._files[idx]
  293. path = item['name']
  294. if item['isdir']:
  295. # Change directory
  296. self._StartBusy(True)
  297. self._client.ChangeDirAsync(path)
  298. else:
  299. # Retrieve the file
  300. self.OpenFile(path)
  301. def OnMenu(self, evt):
  302. """Handle menu events"""
  303. e_id = evt.GetId()
  304. sel = self._list.GetFirstSelected()
  305. path = None
  306. item = None
  307. if sel > -1 and sel < len(self._files):
  308. item = self._files[sel]
  309. path = item['name']
  310. if e_id == ID_EDIT:
  311. # Open the selected file in the editor
  312. if path is not None:
  313. self.OpenFile(path)
  314. elif e_id == ID_RENAME:
  315. # Rename the selected file
  316. if path is not None:
  317. name = wx.GetTextFromUser(_("Enter the new name"),
  318. _("Rename File"))
  319. if len(name):
  320. self._select = name
  321. self._StartBusy(True)
  322. self._client.RenameAsync(path, name)
  323. elif e_id == ID_DELETE:
  324. # Remove the selected path
  325. # TODO: add support for removing directories
  326. if path is not None:
  327. result = wx.MessageBox(_("Are you sure you want to delete %s?") % path,
  328. _("Delete File?"),
  329. style=wx.YES_NO|wx.CENTER|wx.ICON_WARNING)
  330. if result == wx.YES:
  331. self._client.DeleteFileAsync(path)
  332. elif e_id == ID_REFRESH:
  333. # Refresh the file list
  334. self._select = path
  335. self.RefreshFiles()
  336. elif e_id in (ID_NEW_FILE, ID_NEW_FOLDER):
  337. # if item is not None:
  338. # TODO: change to create the new file/folder in the subdirectory
  339. # when the selected item is a directory.
  340. # if item['isdir']:
  341. # pass
  342. # else:
  343. # pass
  344. # Prompt for the new name
  345. if e_id == ID_NEW_FILE:
  346. name = wx.GetTextFromUser(_("Enter name for new file."),
  347. _("New File"))
  348. # Check if the file already exists
  349. found = self._list.FindItem(-1, name)
  350. if found == wx.NOT_FOUND and len(name):
  351. self._select = name
  352. self._client.NewFileAsync(name)
  353. else:
  354. name = wx.GetTextFromUser(_("Enter name for new directory."),
  355. _("New Directory"))
  356. # Check if the file already exists
  357. found = self._list.FindItem(-1, name)
  358. if found == wx.NOT_FOUND and len(name):
  359. self._select = name
  360. self._client.NewDirAsync(name)
  361. if found != wx.NOT_FOUND and len(name):
  362. wx.MessageBox(_("%s already exists. Please enter a different name." % name),
  363. _("%s already exists" % name),
  364. style=wx.OK|wx.CENTER|wx.ICON_WARNING)
  365. elif e_id == ID_COPY_URL:
  366. # Copy the url of the selected file to the clipboard
  367. url = u"/".join([u"ftp:/", self._client.GetHostname().lstrip(u"/"),
  368. self._client.GetCurrentDirectory().lstrip(u"/"),
  369. path.lstrip(u"/")])
  370. util.SetClipboardText(url)
  371. # TODO: add general upload and download functionality
  372. elif e_id == ID_DOWNLOAD:
  373. pass
  374. elif e_id == ID_UPLOAD:
  375. pass
  376. else:
  377. evt.Skip()
  378. def OnRefresh(self, evt):
  379. """Update the file list when a refresh event is sent by our
  380. ftp client.
  381. @param evt: ftpclient.EVT_FTP_REFRESH
  382. """
  383. # Only update the list if the event came from an object of the same
  384. # directory. The directory could be different if the event came
  385. # from a clone of our client.
  386. cwd = self._client.GetCurrentDirectory()
  387. ecwd = evt.GetDirectory()
  388. if cwd != ecwd:
  389. self._StartBusy(False)
  390. return
  391. # No selection was set so see if one is there now
  392. if self._select is None:
  393. sel = self._list.GetFirstSelected()
  394. path = None
  395. item = None
  396. if sel > -1 and sel < len(self._files):
  397. item = self._files[sel]
  398. path = item['name']
  399. self._select = path
  400. if self._list.GetItemCount():
  401. self._list.DeleteAllItems()
  402. # Check for errors
  403. err = self._client.GetLastError()
  404. if err is not None:
  405. wx.MessageBox(_("Error: %s") % err, _("Ftp Error"),
  406. style=wx.OK|wx.CENTER|wx.ICON_ERROR)
  407. self._client.ClearLastError()
  408. self._StartBusy(False)
  409. self._client.Disconnect()
  410. self._HandleDisconnect()
  411. return
  412. # Refresh the file list
  413. self._files = evt.GetValue()
  414. for item in self._files:
  415. self._list.AddItem(item)
  416. self._StartBusy(False)
  417. # Try to reset the previous selection if there was one
  418. if self._select is not None:
  419. index = self._list.FindItem(-1, self._select)
  420. self._select = None
  421. if index != wx.NOT_FOUND:
  422. self._list.EnsureVisible(index)
  423. self._list.SetItemState(index,
  424. wx.LIST_STATE_SELECTED,
  425. wx.LIST_MASK_STATE)
  426. def OnThemeChanged(self, msg):
  427. """Update icons when the theme changes
  428. @param msg: ed_msg.EDMSG_THEME_CHANGED
  429. """
  430. bmp = wx.ArtProvider.GetBitmap(str(ed_glob.ID_PREF), wx.ART_MENU)
  431. pref = self._cbar.FindWindowById(wx.ID_PREFERENCES)
  432. pref.SetBitmap(bmp)
  433. self._cbar.Layout()
  434. def OpenFile(self, path):
  435. """Open a file from the connected ftp site
  436. @param path: file name
  437. """
  438. ed_msg.PostMessage(ed_msg.EDMSG_UI_SB_TXT,
  439. (ed_glob.SB_INFO,
  440. _("Retrieving file") + u"..."))
  441. self._StartBusy(True)
  442. self._client.DownloadAsync(path)
  443. def RefreshControlBar(self):
  444. """Refresh the status of the control bar"""
  445. csel = self._sites.GetStringSelection()
  446. sites = self._config.GetSites()
  447. self._sites.SetItems(sites)
  448. if csel in sites:
  449. self._sites.SetStringSelection(csel)
  450. elif len(sites):
  451. self._sites.SetSelection(0)
  452. csel = self._sites.GetStringSelection()
  453. data = self._config.GetSiteData(csel)
  454. self._username.SetValue(self._config.GetSiteUsername(csel))
  455. self._password.SetValue(self._config.GetSitePassword(csel))
  456. self._cbar.Layout()
  457. self.EnableControls(len(sites))
  458. def RefreshFiles(self):
  459. """Refresh the current view"""
  460. self._StartBusy(True)
  461. self._client.RefreshPath()
  462. #-----------------------------------------------------------------------------#
  463. class FtpList(listmix.ListCtrlAutoWidthMixin,
  464. eclib.ListRowHighlighter,
  465. wx.ListCtrl):
  466. """Ftp File List
  467. Displays the list of files in the currently connected ftp site.
  468. """
  469. def __init__(self, parent, id_=wx.ID_ANY):
  470. wx.ListCtrl.__init__(self, parent, id_,
  471. style=wx.LC_REPORT|wx.LC_SINGLE_SEL)
  472. eclib.ListRowHighlighter.__init__(self)
  473. # Attributes
  474. self._il = wx.ImageList(16, 16)
  475. self._idx = dict()
  476. self._menu = None
  477. # Setup
  478. font = Profile_Get('FONT3', 'font', wx.NORMAL_FONT)
  479. self.SetFont(font)
  480. self.SetupImageList()
  481. self.InsertColumn(0, _("Filename"))
  482. self.InsertColumn(1, _("Size"))
  483. self.InsertColumn(2, _("Modified"))
  484. # Setup autowidth
  485. listmix.ListCtrlAutoWidthMixin.__init__(self)
  486. self.setResizeColumn(1) # <- NOTE: autowidth mixin starts from index 1
  487. # Event Handlers
  488. self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.OnContextMenu)
  489. self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy, self)
  490. # Message Handlers
  491. ed_msg.Subscribe(self.OnThemeChanged, ed_msg.EDMSG_THEME_CHANGED)
  492. ed_msg.Subscribe(self.OnUpdateFont, ed_msg.EDMSG_DSP_FONT)
  493. def OnDestroy(self, evt):
  494. """Unsubscribe from messages"""
  495. if self:
  496. ed_msg.Unsubscribe(self.OnThemeChanged)
  497. ed_msg.Unsubscribe(self.OnUpdateFont)
  498. if self._menu:
  499. self._menu.Destroy()
  500. def AddItem(self, item):
  501. """Add an item to the list
  502. @param item: dict(isdir, name, size, date)
  503. """
  504. self.Append((item['name'], item['size'], item['date']))
  505. if item['isdir']:
  506. img = self._idx['folder']
  507. else:
  508. img = self._idx['file']
  509. self.SetItemImage(self.GetItemCount() - 1, img)
  510. self.resizeLastColumn(self.GetTextExtent(u"Dec 31 24:00:00")[0] + 5)
  511. def OnContextMenu(self, evt):
  512. """Show the context menu"""
  513. if not self.GetSelectedItemCount():
  514. evt.Skip()
  515. return
  516. if self._menu is None:
  517. # Lazy init menu
  518. self._menu = wx.Menu()
  519. item = self._menu.Append(ID_REFRESH, _("Refresh"))
  520. bmp = wx.ArtProvider.GetBitmap(str(ed_glob.ID_REFRESH), wx.ART_MENU)
  521. if not bmp.IsNull():
  522. item.SetBitmap(bmp)
  523. self._menu.AppendSeparator()
  524. self._menu.Append(ID_EDIT, _("Edit"))
  525. self._menu.Append(ID_RENAME, _("Rename") + u"...")
  526. item = self._menu.Append(ID_DELETE, _("Delete"))
  527. bmp = wx.ArtProvider.GetBitmap(str(ed_glob.ID_DELETE), wx.ART_MENU)
  528. if not bmp.IsNull():
  529. item.SetBitmap(bmp)
  530. self._menu.AppendSeparator()
  531. item = self._menu.Append(ID_NEW_FILE, _("New File") + u"...")
  532. bmp = wx.ArtProvider.GetBitmap(str(ed_glob.ID_NEW), wx.ART_MENU)
  533. if not bmp.IsNull():
  534. item.SetBitmap(bmp)
  535. item = self._menu.Append(ID_NEW_FOLDER, _("New Folder") + u"...")
  536. bmp = wx.ArtProvider.GetBitmap(str(ed_glob.ID_FOLDER), wx.ART_MENU)
  537. if not bmp.IsNull():
  538. item.SetBitmap(bmp)
  539. self._menu.AppendSeparator()
  540. self._menu.Append(ID_COPY_URL, _("Copy URL"))
  541. # TODO: Add in Version 0.3
  542. # self._menu.AppendSeparator()
  543. # self._menu.Append(ID_DOWNLOAD, _("Download") + u"...")
  544. # self._menu.Append(ID_UPLOAD, _("Upload") + u"...")
  545. # Update the menu state for the current selection
  546. self.UpdateMenuState()
  547. self.PopupMenu(self._menu)
  548. def OnThemeChanged(self, msg):
  549. """Update image list
  550. @param msg: ed_msg.EDMSG_THEME_CHANGED
  551. """
  552. bmp = wx.ArtProvider.GetBitmap(str(ed_glob.ID_FOLDER), wx.ART_MENU)
  553. self._il.Replace(self._idx['folder'], bmp)
  554. bmp = wx.ArtProvider.GetBitmap(str(ed_glob.ID_FILE), wx.ART_MENU)
  555. self._il.Replace(self._idx['file'], bmp)
  556. self.Refresh()
  557. def OnUpdateFont(self, msg):
  558. """Update the ui font when changed."""
  559. font = msg.GetData()
  560. if isinstance(font, wx.Font) and not font.IsNull():
  561. self.SetFont(font)
  562. def SetupImageList(self):
  563. """Setup the image list"""
  564. bmp = wx.ArtProvider.GetBitmap(str(ed_glob.ID_FOLDER), wx.ART_MENU)
  565. self._idx['folder'] = self._il.Add(bmp)
  566. bmp = wx.ArtProvider.GetBitmap(str(ed_glob.ID_FILE), wx.ART_MENU)
  567. self._idx['file'] = self._il.Add(bmp)
  568. self.SetImageList(self._il, wx.IMAGE_LIST_SMALL)
  569. def UpdateMenuState(self):
  570. """Update the current state of the context menu"""
  571. if self._menu is not None:
  572. idx = self.GetFirstSelected()
  573. item = None
  574. isdir = False
  575. if idx != wx.NOT_FOUND:
  576. item = self.GetItem(idx)
  577. isdir = item.GetImage() == self._idx['folder']
  578. for id_ in (ID_EDIT, ID_DELETE): # ID_DOWNLOAD
  579. mitem = self._menu.FindItemById(id_)
  580. mitem.Enable(item and not isdir)
  581. if item is not None:
  582. lbl = item.GetText()
  583. mitem = self._menu.FindItemById(ID_RENAME)
  584. if isdir and lbl == u"..":
  585. mitem.Enable(False)
  586. else:
  587. mitem.Enable(True)