PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/bundles/plugins-trunk/Sessions/sessions/SessionManager.java

#
Java | 589 lines | 305 code | 88 blank | 196 comment | 47 complexity | 98879bdf1a28f707dcff71d808cb48f4 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * SessionManager.java
  3. * Copyright (c) 2001 Dirk Moebius, Sergey V. Udaltsov
  4. * Copyright (c) 2007, 2008 Steve Jakob
  5. *
  6. * :tabSize=4:indentSize=4:noTabs=false:maxLineLen=0:
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package sessions;
  23. import java.awt.Component;
  24. import java.io.File;
  25. import java.io.FilenameFilter;
  26. import java.io.FileNotFoundException;
  27. import java.io.IOException;
  28. import java.util.Arrays;
  29. import java.util.Vector;
  30. import javax.swing.JOptionPane;
  31. import org.gjt.sp.jedit.*;
  32. import org.gjt.sp.jedit.browser.VFSBrowser;
  33. import org.gjt.sp.jedit.io.VFSManager;
  34. import org.gjt.sp.jedit.msg.PropertiesChanged;
  35. import org.gjt.sp.util.Log;
  36. import org.gjt.sp.util.StandardUtilities;
  37. import org.gjt.sp.jedit.msg.BufferUpdate;
  38. /**
  39. * A singleton class that holds a current session and acts as a controller for handling
  40. * session management tasks.
  41. *
  42. * <h1>Saving Sessions</code>
  43. * <p>There are two different types of situations that may result in a session being
  44. * saved, each of which is handled differently. These are:</p>
  45. * <ul>
  46. * <li><b>User-requested save</b>: occurs when the user manually requests that a session be
  47. * saved, either from the session switcher component or the session manager dialog. In
  48. * this cases there is no need to confirm the user's desire to save the session, but the
  49. * user will be notified following a successful save. This type of save is handled by
  50. * the #saveCurrentSession(View) method.</li>
  51. * <li><b>Autosave</b>: occurs when the user initiates an action that results in the
  52. * current session being closed. Such actions include switching to a different session,
  53. * renaming a session, or shutting down the plugin. In this cases, the user might be
  54. * shown a dialog to confirm his/her desire to save (unless the users' preferences indicate
  55. * that no confirmation is desired), but no confirmation of save sucess is given. This type
  56. * of save is handled by the #autosaveCurrentSession method.</li>
  57. * </ul>
  58. */
  59. public class SessionManager implements EBComponent
  60. {
  61. public final static String SESSION_PROPERTY = "sessions.currentSession";
  62. /** The current session instance. */
  63. private Session currentSession;
  64. /** The singleton SessionManager instance. */
  65. private static SessionManager instance;
  66. /** The string that will contain the new temp jEdit view.title property.*/
  67. private String titleBarSessionName;
  68. /** The default jEdit view.title property. */
  69. private String defaultViewTitle;
  70. /** Returns the singleton SessionManager instance */
  71. public static SessionManager getInstance()
  72. {
  73. if(instance == null)
  74. instance = new SessionManager();
  75. return instance;
  76. }
  77. /**
  78. * Initialization
  79. */
  80. private SessionManager()
  81. {
  82. currentSession = new Session(jEdit.getProperty(SESSION_PROPERTY, "default"));
  83. // create directory <jedithome>/sessions if it not yet exists
  84. File dir = new File(getSessionsDir());
  85. if(!dir.exists())
  86. dir.mkdirs();
  87. // convert old format session files, if necessary
  88. new SessionFileConverter().run();
  89. // create default session file if it not yet exists
  90. File defaultSessionFile = new File(createSessionFileName("default"));
  91. if(!defaultSessionFile.exists())
  92. new Session("default").save(null);
  93. // initialize the variables for the jEdit title bar
  94. defaultViewTitle = jEdit.getProperty("view.title",
  95. jEdit.getProperty("sessions.titlebar.default"));
  96. titleBarSessionName = new String();
  97. }
  98. /**
  99. * Save the current session (subject to user preferences) and switch to a new session.
  100. * This sends out a SessionChanged message on EditBus, if the
  101. * session could be changed successfully.
  102. *
  103. * @param view view for displaying error messages
  104. * @param newSession the new session name
  105. * @return false, if the new session could not be set.
  106. */
  107. public void setCurrentSession(final View view, final String newSessionName)
  108. {
  109. if(newSessionName.equals(currentSession.getName()))
  110. return;
  111. Log.log(Log.DEBUG, this, "setCurrentSession:"
  112. + " currentSession=" + currentSession.getName()
  113. + " newSessionName=" + newSessionName);
  114. File currentSessionFile = new File(currentSession.getFilename());
  115. if(currentSessionFile.exists())
  116. {
  117. // Auto-save the current session, subject to user preferences.
  118. if (!autosaveCurrentSession(view))
  119. {
  120. // User doesn't want to switch the session
  121. return;
  122. }
  123. }
  124. else
  125. {
  126. // The current session file has been deleted, probably by the SessionManagerDialog.
  127. // Do nothing, because save would recreate it.
  128. }
  129. // close all open buffers, if closeAll option is set:
  130. if (jEdit.getBooleanProperty("sessions.switcher.closeAll", true))
  131. if (!jEdit.closeAllBuffers(view))
  132. return; // jEdit should have shown an error
  133. final String oldSessionName = currentSession.getName();
  134. EditBus.send(new SessionChanging(this, oldSessionName, newSessionName));
  135. // load new session
  136. // make sure this is not done from the AWT thread
  137. // {{{ This section changed by Steve Jakob
  138. // Opening the new session in a separate thread would occasionally
  139. // cause jEdit to freeze. I've left the code here in case we wish to try
  140. // this sort of thing in the future.
  141. /*
  142. new Thread()
  143. {
  144. public void run()
  145. {
  146. currentSession = new Session(newSessionName);
  147. saveCurrentSessionProperty();
  148. currentSession.open(view);
  149. EditBus.send(new SessionChanged(
  150. SessionManager.this, oldSessionName, newSessionName, currentSession));
  151. }
  152. }.start();
  153. */
  154. currentSession = new Session(newSessionName);
  155. saveCurrentSessionProperty();
  156. currentSession.open(view);
  157. EditBus.send(new SessionChanged(
  158. SessionManager.this, oldSessionName, newSessionName, currentSession));
  159. // }}} End of section changed by Steve Jakob
  160. // Change FSB directory if appropriate
  161. changeFSBToBaseDirectory(view);
  162. // update the jEdit title bar with the session name
  163. setSessionNameInTitleBar();
  164. }
  165. /** Return the current session name. */
  166. public String getCurrentSession()
  167. {
  168. return currentSession.getName();
  169. }
  170. /** Return the current session. */
  171. public Session getCurrentSessionInstance()
  172. {
  173. return currentSession;
  174. }
  175. /**
  176. * Save current session and show a dialog that it has been saved. This is the method
  177. * that is called for a "user-requested" save operation.
  178. *
  179. * @param view view for displaying error messages
  180. */
  181. public void saveCurrentSession(View view)
  182. {
  183. saveCurrentSession(view, false);
  184. }
  185. /**
  186. * Save current session without showing the save confirmation dialog,
  187. * unless the "display confirmation dialog" flag has been set in the
  188. * plugin properties pane. This is the method that is called for "autosave"
  189. * functionality (ie. switching sessions, renaming a session, or shutting
  190. * down the plugin).
  191. *
  192. * @param view view for displaying error messages
  193. * @return <code>false</code> if the autosave process has been cancelled
  194. */
  195. public boolean autosaveCurrentSession(View view)
  196. {
  197. if (currentSession.hasFileListChanged())
  198. {
  199. // If autosave sessions is on, save current session silently.
  200. if (jEdit.getBooleanProperty("sessions.switcher.autoSave", true))
  201. {
  202. // If the "askSave" property is set to "true" ...
  203. if (jEdit.getBooleanProperty("sessions.switcher.askSave", false))
  204. {
  205. // ... confirm whether the session should be saved
  206. boolean ok = new SaveDialog(view).isOK();
  207. if (!ok)
  208. {
  209. // User doesn't want to save the session
  210. return false;
  211. }
  212. }
  213. else
  214. {
  215. // Save the session.
  216. Log.log(Log.DEBUG, this, "autosaving current session...");
  217. saveCurrentSession(view, true);
  218. }
  219. }
  220. }
  221. return true;
  222. }
  223. /**
  224. * Save current session. NOTE: developers should not call this method directly. Instead,
  225. * either the #saveCurrentSession(View) or #autosaveCurrentSession method should be
  226. * used, depending on the nature of the save operation.
  227. *
  228. * @param view view for displaying error messages
  229. * @param silently if false, show a dialog that the current session has been saved.
  230. */
  231. public void saveCurrentSession(View view, boolean silently)
  232. {
  233. currentSession.save(view);
  234. saveCurrentSessionProperty();
  235. if (!silently)
  236. {
  237. GUIUtilities.message(view, "sessions.switcher.save.saved",
  238. new Object[] { currentSession });
  239. }
  240. Log.log(Log.DEBUG, this, "session saved: " + currentSession.getName());
  241. }
  242. /**
  243. * Save current session under a different name and switch to it.
  244. * This sends out SessionListChanged and SessionChanged messages
  245. * on EditBus, if the session could be changed successfully, in this
  246. * order.
  247. *
  248. * @param view view for displaying error messages
  249. */
  250. public void saveCurrentSessionAs(View view)
  251. {
  252. String newName = inputSessionName(view, currentSession.getName());
  253. if (newName == null)
  254. return;
  255. File file = new File(createSessionFileName(newName));
  256. if (file.exists())
  257. {
  258. int answer = GUIUtilities.confirm(view,
  259. "sessions.switcher.saveAs.exists",
  260. new Object[] { newName },
  261. JOptionPane.YES_NO_OPTION,
  262. JOptionPane.WARNING_MESSAGE
  263. );
  264. if (answer != JOptionPane.YES_OPTION)
  265. return;
  266. }
  267. // create new session:
  268. Session newSession = currentSession.getClone();
  269. newSession.setName(newName);
  270. newSession.save(view);
  271. EditBus.send(new SessionChanging(this, currentSession.getName(), newName));
  272. // set new session:
  273. String oldSessionName = currentSession.getName();
  274. currentSession = newSession;
  275. saveCurrentSessionProperty();
  276. EditBus.send(new SessionListChanged(this));
  277. EditBus.send(new SessionChanged(this, oldSessionName, newName, currentSession));
  278. // update the jEdit title bar with the session name
  279. setSessionNameInTitleBar();
  280. }
  281. /**
  282. * Reload current session.
  283. *
  284. * @param view view for displaying error messages
  285. */
  286. public void reloadCurrentSession(final View view)
  287. {
  288. Log.log(Log.DEBUG, this, "reloadCurrentSession: currentSession=" + currentSession);
  289. // close all open buffers
  290. if(!jEdit.closeAllBuffers(view))
  291. return; // user cancelled
  292. // FIXME: do we need to make sure this is not the AWT thread?!?
  293. currentSession.open(view); // ignore any errors and return value
  294. }
  295. /**
  296. * Change FSB directory if relevant option selected, "basedir" property
  297. * set, and FSB is visible.
  298. *
  299. * @param view look for FSB in this View
  300. */
  301. public void changeFSBToBaseDirectory(View view)
  302. {
  303. if ((jEdit.getBooleanProperty("sessions.switcher.changeFSBDirectory", false)) &&
  304. !("".equals(currentSession.getProperty(Session.BASE_DIRECTORY))) &&
  305. (view.getDockableWindowManager().isDockableWindowVisible(VFSBrowser.NAME)))
  306. {
  307. VFSBrowser.browseDirectory(view,
  308. currentSession.getProperty(Session.BASE_DIRECTORY));
  309. }
  310. }
  311. /**
  312. * Show the Session Manager dialog.
  313. * If the user changes the current session or modifies the
  314. * list of sessions, SessionChanged and SessionListChanged
  315. * messages are sent on EditBus.
  316. *
  317. * @param view center dialog on this View.
  318. */
  319. public void showSessionManagerDialog(View view)
  320. {
  321. SessionManagerDialog dlg = new SessionManagerDialog(view, currentSession.getName());
  322. String newSession = dlg.getSelectedSession();
  323. if(dlg.isListModified())
  324. {
  325. EditBus.send(new SessionListChanged(this));
  326. if(newSession == null)
  327. {
  328. // Session list has been modified, but dialog has been cancelled.
  329. // Send out session changed events, just in case...
  330. String name = currentSession.getName();
  331. EditBus.send(new SessionChanging(this, name, name));
  332. EditBus.send(new SessionChanged(this, name, name, currentSession));
  333. }
  334. }
  335. if(newSession != null)
  336. setCurrentSession(view, newSession);
  337. }
  338. public void showSessionPropertiesDialog(View view)
  339. {
  340. SessionPropertiesShowing message = new SessionPropertiesShowing(this, currentSession);
  341. EditBus.send(message);
  342. new SessionPropertiesDialog(view, currentSession.getName(), message.getRootGroup());
  343. }
  344. public static String[] getSessionNames()
  345. {
  346. String[] files = new File(getSessionsDir()).list(new FilenameFilter()
  347. {
  348. public boolean accept(File dir, String name)
  349. {
  350. return name.toLowerCase().endsWith(".xml");
  351. }
  352. });
  353. Arrays.sort(files, new StandardUtilities.StringCompare(false));
  354. Vector v = new Vector();
  355. boolean foundDefault = false;
  356. for (int i=0; i < files.length; i++)
  357. {
  358. String name = files[i].substring(0, files[i].length() - 4); // cut off ".xml"
  359. if (name.equalsIgnoreCase("default"))
  360. {
  361. // default session always first
  362. v.insertElementAt(name, 0);
  363. foundDefault = true;
  364. }
  365. else
  366. v.addElement(name);
  367. }
  368. if (!foundDefault)
  369. v.insertElementAt("default", 0);
  370. String[] result = new String[v.size()];
  371. v.copyInto(result);
  372. return result;
  373. }
  374. /** EBComponent implementation; does nothing */
  375. public void handleMessage(EBMessage msg) {}
  376. /**
  377. * Converts a session name (eg, "default") to a full path name
  378. * (eg, "/home/slava/.jedit/sessions/default.xml").
  379. */
  380. public static String createSessionFileName(String session)
  381. {
  382. String filename = MiscUtilities.constructPath(getSessionsDir(), session);
  383. if (!filename.toLowerCase().endsWith(".xml"))
  384. filename = filename + ".xml";
  385. return filename;
  386. }
  387. /**
  388. * Return the directory where the session files are stored,
  389. * usually $HOME/.jedit/sessions.
  390. */
  391. public static String getSessionsDir()
  392. {
  393. return MiscUtilities.constructPath(jEdit.getSettingsDirectory(), "sessions");
  394. }
  395. /**
  396. * Shows an input dialog asking for a session name as long as a valid
  397. * session name is entered or the dialog is cancelled.
  398. * A session name is valid if it doesn't contains the following characters:
  399. * File.separatorChar, File.pathSeparatorChar and ':'.
  400. *
  401. * @param relativeTo the component where the dialog is centered on.
  402. * @param defaultName a default session name to display in the input dialog; may be null.
  403. * @return the new session name, or null if the dialog was cancelled.
  404. */
  405. public static String inputSessionName(Component relativeTo, String defaultName)
  406. {
  407. String name = defaultName;
  408. do
  409. {
  410. name = GUIUtilities.input(relativeTo, "sessions.switcher.saveAs.input", name);
  411. if (name != null)
  412. {
  413. name = name.trim();
  414. if (name.length() == 0)
  415. GUIUtilities.error(relativeTo, "sessions.switcher.saveAs.error.empty", null);
  416. if (name.indexOf('/') >= 0 || name.indexOf('\\') >= 0
  417. || name.indexOf(';') >= 0 || name.indexOf(':') >= 0)
  418. {
  419. GUIUtilities.error(relativeTo, "sessions.switcher.saveAs.error.illegalChars", new Object[] { "/ \\ ; :" });
  420. name = "";
  421. }
  422. }
  423. } while (name != null && name.length() == 0);
  424. return name;
  425. }
  426. /**
  427. * Show an error message dialog (using GUIUtilities.error())
  428. * after the GUI has been updated, in the AWT thread.
  429. */
  430. public static final void showErrorLater(final View view, final String messageProperty, final Object[] args)
  431. {
  432. VFSManager.runInAWTThread(new Runnable()
  433. {
  434. public void run()
  435. {
  436. GUIUtilities.error(view, messageProperty, args);
  437. }
  438. });
  439. }
  440. // {{{ jEdit title bar controls
  441. // added by Paul Russell 2004-09-26
  442. /**
  443. * Record the name of the current session in a jEdit property (SESSION_PROPERTY). This
  444. * property is used to restore the last used session the next time the plugin is started.
  445. */
  446. void saveCurrentSessionProperty()
  447. {
  448. Log.log(Log.DEBUG, this, "saveCurrentSessionProperty: currentSession=" + currentSession.getName());
  449. jEdit.setProperty(SESSION_PROPERTY, currentSession.getName());
  450. jEdit.saveSettings();
  451. }
  452. /**
  453. * Put the session name in the jEdit title bar
  454. */
  455. public void setSessionNameInTitleBar()
  456. {
  457. if ( currentSession != null )
  458. {
  459. if ( jEdit.getBooleanProperty("sessions.switcher.showSessionNameInTitleBar", true) )
  460. {
  461. if (jEdit.getBooleanProperty("sessions.switcher.showSessionPrefixInTitleBar", true))
  462. {
  463. titleBarSessionName = defaultViewTitle +
  464. jEdit.getProperty("sessions.titlebar.startbracket") +
  465. jEdit.getProperty("sessions.titlebar.prefix") +
  466. currentSession.getName() +
  467. jEdit.getProperty("sessions.titlebar.endbracket");
  468. }
  469. else
  470. {
  471. titleBarSessionName = defaultViewTitle +
  472. jEdit.getProperty("sessions.titlebar.startbracket") +
  473. currentSession.getName() +
  474. jEdit.getProperty("sessions.titlebar.endbracket");
  475. }
  476. jEdit.setTemporaryProperty("view.title", titleBarSessionName);
  477. refreshTitleBar();
  478. }
  479. }
  480. }
  481. /**
  482. * Restore the original jEdit title bar text
  483. */
  484. public void restoreTitleBarText()
  485. {
  486. jEdit.setTemporaryProperty("view.title", defaultViewTitle);
  487. }
  488. /**
  489. * refreshes the jEdit Title Bar. This only needs to be called
  490. * when the plugin stops or restarts.
  491. */
  492. public void refreshTitleBar()
  493. {
  494. View[] views = jEdit.getViews();
  495. for( int i = 0; i < views.length; i++ )
  496. {
  497. views[i].updateTitle();
  498. }
  499. }
  500. // }}}
  501. }