PageRenderTime 30ms CodeModel.GetById 8ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

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

#
Java | 585 lines | 381 code | 74 blank | 130 comment | 30 complexity | 19fbb9f2b034a551fe5242ec44fba3e4 MD5 | raw file
  1/*
  2 * Session.java - represents a jEdit session
  3 * Copyright (c) 2001 Dirk Moebius
  4 * Copyright (c) 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
 23package sessions;
 24
 25import java.io.BufferedReader;
 26import java.io.BufferedWriter;
 27import java.io.File;
 28import java.io.FileInputStream;
 29import java.io.FileWriter;
 30import java.io.IOException;
 31import java.io.InputStreamReader;
 32import java.util.Enumeration;
 33import java.util.Hashtable;
 34import java.util.Iterator;
 35import java.util.Vector;
 36
 37import org.gjt.sp.jedit.Buffer;
 38import org.gjt.sp.jedit.EditBus;
 39import org.gjt.sp.jedit.View;
 40import org.gjt.sp.jedit.jEdit;
 41import org.gjt.sp.util.Log;
 42import org.gjt.sp.util.XMLUtilities;
 43import org.xml.sax.Attributes;
 44import org.xml.sax.InputSource;
 45import org.xml.sax.SAXException;
 46import org.xml.sax.helpers.DefaultHandler;
 47
 48
 49public class Session implements Cloneable
 50{
 51
 52	/** Session Property name for Session base directory */
 53	public static final String BASE_DIRECTORY = "basedir";
 54	/** Session Property name for Session default edit mode */
 55	public static final String DEFAULT_MODE = "mode";
 56
 57	private String name;
 58	private String filename;
 59	private String currentFile;
 60	private Hashtable properties, sessionFiles;
 61
 62
 63	public Session(String name)
 64	{
 65		setName(name);
 66		this.sessionFiles = new Hashtable();
 67		this.properties = new Hashtable();
 68	}
 69
 70
 71	public String getName()
 72	{
 73		return name;
 74	}
 75
 76
 77	public void setName(String name)
 78	{
 79		this.name = name;
 80		this.filename = SessionManager.createSessionFileName(name);
 81	}
 82
 83	/**
 84	 * Rename this session. This changes both the logical name and the filename.
 85	 * @param newName The new name for the session.
 86	 * @return <code>true</code> if the rename succeeds, <code>false</code> otherwise.
 87	 */
 88	public boolean rename(String newName)
 89	{
 90		String oldName = this.name;
 91		File oldFile = new File(this.filename);
 92		File newFile = new File(SessionManager.createSessionFileName(newName));
 93		if (oldFile.renameTo(newFile) == false)
 94		{
 95			// rename failed, so ...
 96			return false;
 97		}
 98		setName(newName);
 99		// Re-save so that the file contains the updated Session name
100		try {
101			saveXML();
102		} catch (IOException ioe) {
103			setName(oldName);
104			return false;
105		}
106		return true;
107	}
108
109
110	public String getFilename()
111	{
112		return filename;
113	}
114
115
116	public String toString()
117	{
118		return name;
119	}
120
121
122	public void setCurrentFile(String file)
123	{
124		if(hasFile(file))
125			currentFile = file;
126		else
127			Log.log(Log.DEBUG, this, "setCurrentFile: session " + name + ": doesn't contain file " + file + " - use addFile() first.");
128	}
129
130
131	public String getCurrentFile()
132	{
133		return currentFile;
134	}
135
136
137	/**
138	 * Get a session property.
139	 *
140	 * @return the session property value, of null if the specified key
141	 *    cannot be found.
142	 */
143	public String getProperty(String key)
144	{
145		Object value = properties.get(key);
146		return value == null ? null : value.toString();
147	}
148
149
150	/**
151	 * Set a session property.
152	 * This sends out a SessionPropertyChanged message on EditBus.
153	 * Note that having a value of <code>null</code> is the same as
154	 * removeProperty(key), in which case a SessionPropertyRemoved
155	 * message is sent out on EditBus.
156	 *
157	 * @throws NullPointerException if key is null.
158	 */
159	public void setProperty(String key, String value)
160	{
161		if(value != null)
162		{
163			Object oldValue = properties.put(key, value);
164			EditBus.send(new SessionPropertyChanged(
165				SessionManager.getInstance(), this, key,
166				oldValue != null ? oldValue.toString() : null, value));
167		}
168		else
169			removeProperty(key);
170	}
171
172
173	// being nice to developers: some convenience methods for storing/retrieving primitives
174
175	public int getIntProperty(String key, int defaultValue) { return ParseUtilities.toInt(getProperty(key), defaultValue); }
176	public long getLongProperty(String key, long defaultValue) { return ParseUtilities.toLong(getProperty(key), defaultValue); }
177	public boolean getBooleanProperty(String key, boolean defaultValue) { return ParseUtilities.toBoolean(getProperty(key), defaultValue); }
178	public float getFloatProperty(String key, float defaultValue) { return ParseUtilities.toFloat(getProperty(key), defaultValue); }
179	public double getDoubleProperty(String key, double defaultValue) { return ParseUtilities.toDouble(getProperty(key), defaultValue); }
180	public String getProperty(String key, String defaultValue) { String s = getProperty(key); return s != null ? s : defaultValue; }
181
182	public void setIntProperty(String key, int value) { setProperty(key, String.valueOf(value)); }
183	public void setLongProperty(String key, long value) { setProperty(key, String.valueOf(value)); }
184	public void setBooleanProperty(String key, boolean value) { setProperty(key, String.valueOf(value)); }
185	public void setFloatProperty(String key, float value) { setProperty(key, String.valueOf(value)); }
186	public void setDoubleProperty(String key, double value) { setProperty(key, String.valueOf(value)); }
187
188
189	/**
190	 * Remove a session property.
191	 * If the property was part of this session, a SessionPropertyRemoved
192	 * message is sent out on EditBus. If the session didn't contain
193	 * the property, nothing is sent.
194	 *
195	 * @throws NullPointerException if key is null.
196	 */
197	public void removeProperty(String key)
198	{
199		if(properties.containsKey(key))
200		{
201			Object oldValue = properties.remove(key);
202			EditBus.send(new SessionPropertyRemoved(
203				SessionManager.getInstance(), this, key,
204				oldValue != null ? oldValue.toString() : null));
205		}
206	}
207
208
209	public boolean hasFile(String file)
210	{
211		return sessionFiles.containsKey(file);
212	}
213
214
215	/**
216	 * Returns a <code>java.util.Enumeration</code> containing 
217	 * <code>java.io.File</code> objects corresponding to the files 
218	 * managed by this <code>Session</code> object.
219	 */
220	public Enumeration getAllFiles()
221	{
222		return sessionFiles.elements();
223	}
224
225
226	/**
227	 * Returns a <code>java.util.Enumeration</code> containing 
228	 * <code>String</code> objects corresponding to the names of the files 
229	 * managed by this <code>Session</code> object.
230	 */
231	public Enumeration getAllFilenames()
232	{
233		return sessionFiles.keys();
234	}
235
236
237	/**
238	 * Loads and opens the session.
239	 * The session is loaded from the XML file in the sessions repository,
240	 * then the files of the session are opened.
241	 *
242	 * @see #open(org.gjt.sp.jedit.View, boolean)
243	 * @param view  where to display error message boxes.
244	 * @return  true  if the session was loaded successfully and all buffers
245	 *   have been opened.
246	 */
247	public boolean open(View view)
248	{
249		return open(view, true);
250	}
251
252
253	/**
254	 * Loads and optionally opens the session.
255	 * The session is loaded from the XML file in the sessions repository,
256	 * then the files of the session are opened.
257	 *
258	 * @param view  where to display error message boxes.
259	 * @param openFiles whether or not to open all the session files in addition
260	 *   to loading and parsing the XML file (with its custom properties).
261	 * @return  true  if the session was loaded successfully and all buffers
262	 *   have been opened.
263	 */
264	public boolean open(View view, boolean openFiles)
265	{
266		Log.log(Log.DEBUG, this, "open: name=" + name);
267
268		try
269		{
270			loadXML();
271		}
272		catch (IOException io)
273		{
274			Log.log(Log.ERROR, this, io);
275			SessionManager.showErrorLater(view, "ioerror", new Object[] { io.getMessage() });
276			return false;
277		}
278		catch (Exception e)
279		{
280			// this is probably a xml parse exception
281			Log.log(Log.ERROR, this, e);
282			SessionManager.showErrorLater(view, "sessions.manager.error.load", new Object[] { name, e.getMessage() });
283			return false;
284		}
285
286		if (openFiles)
287		{
288			// open session files:
289			Iterator it = sessionFiles.values().iterator();
290			while(it.hasNext())
291			{
292				SessionFile sf = (SessionFile)it.next();
293				Hashtable props = sf.getBufferProperties();
294				jEdit.openFile(view, null, sf.getPath(), false, props);
295			}
296
297			// open session's recent buffer:
298			if(currentFile != null)
299			{
300				Buffer buffer = jEdit.getBuffer(currentFile);
301				if(buffer != null)
302					view.setBuffer(buffer);
303			}
304		}
305
306		return true;
307	}
308
309
310	/**
311	 * Saves the session.
312	 *
313	 * @param view  The view the session is being saved from.
314	 * @return true, if the session was saved successfully,
315	 *   false if an IOException occurred.
316	 */
317	public boolean save(View view)
318	{
319		Log.log(Log.DEBUG, this, "save: name=" + name);
320
321		if (view != null)
322			view.getEditPane().saveCaretInfo();
323
324		// Right now, the session's file list is cleared and filled again with
325		// the current list of open jEdit buffers, but this behavior could be
326		// changed in the future...
327		sessionFiles.clear();
328
329		for(Buffer buffer = jEdit.getFirstBuffer(); buffer != null; buffer = buffer.getNext())
330			if(!buffer.isUntitled())
331				addFile(buffer.getPath(), buffer.getStringProperty(Buffer.ENCODING));
332
333		if(view != null)
334			currentFile = view.getBuffer().getPath();
335
336		try
337		{
338			saveXML();
339		}
340		catch (IOException io) {
341			Log.log(Log.ERROR, this, io);
342			SessionManager.showErrorLater(view, "ioerror", new Object[] { io.getMessage() });
343			return false;
344		}
345
346		return true;
347	}
348	
349	/**
350	 * Has the the list of opened files changed?
351	 *
352	 * @return <code>true</code> if the file list has not changed
353	 *   since the previous load/update, 
354	 *   <code>false</code> if some file(s) have been opened/closed
355	 */
356	public boolean hasFileListChanged()
357	{
358		Vector currentFiles = new Vector();
359		
360		for(Buffer buffer = jEdit.getFirstBuffer(); buffer != null; buffer = buffer.getNext())
361			if(!buffer.isUntitled())
362				currentFiles.addElement(buffer.getPath());
363		
364		Vector allFiles = new Vector(sessionFiles.values());
365		if (allFiles.equals(currentFiles))
366			return false;
367		
368		return true;
369	}
370
371	/**
372	 * Add a file to the session's file list using the default character encoding.
373	 */
374	public void addFile(String file)
375	{
376		if(hasFile(file))
377			Log.log(Log.DEBUG, this, "addFile: session " + name + ": already contains file " + file + " - not added.");
378		else
379			addFile(file, jEdit.getProperty("buffer.encoding",
380					System.getProperty("file.encoding")));
381	}
382
383	/**
384	 * Add a file to the session's file list using the supplied character encoding.
385	 */
386	public void addFile(String file, String encoding)
387	{
388		if(hasFile(file))
389			Log.log(Log.DEBUG, this, "addFile: session " + name + ": already contains file " + file + " - not added.");
390		else
391			sessionFiles.put(file, new SessionFile(file, encoding));
392	}
393
394	/**
395	 * Clears the session's contents: forgets all open files and properties,
396	 * and the name of the current file.
397	 */
398	public void clear()
399	{
400		sessionFiles.clear();
401		properties.clear();
402		currentFile = null;
403	}
404
405
406	public Object clone()
407	{
408		return getClone();
409	}
410
411
412	public Session getClone()
413	{
414		Session clone = new Session(this.name);
415		clone.sessionFiles = (Hashtable) this.sessionFiles.clone();
416		clone.properties = (Hashtable) this.properties.clone();
417		return clone;
418	}
419
420
421	/**
422	 * Loads the session, but does not open any files in jEdit.
423	 */
424	public void loadXML() throws Exception
425	{
426		Log.log(Log.DEBUG, this, "loadXML: name=" + name + " filename=" + filename);
427
428		clear();
429
430		// Reader reader = new BufferedReader(new FileReader(filename));
431		XMLUtilities.parseXML(new FileInputStream(filename), new SessionXmlHandler());
432		//XmlParser parser = new XmlParser();
433		//parser.setHandler(new SessionXmlHandler(parser));
434		//parser.parse(null, null, reader);
435	}
436
437
438	/**
439	 * Saves the session.
440	 */
441	public void saveXML() throws IOException
442	{
443		Log.log(Log.DEBUG, this, "saveXML: name=" + name + " filename=" + filename);
444
445		BufferedWriter out = new BufferedWriter(new FileWriter(filename));
446		// write header
447		out.write("<?xml version=\"1.0\"?>");
448		out.newLine();
449		out.write("<!DOCTYPE SESSION SYSTEM \"session.dtd\">");
450		out.newLine();
451		out.newLine();
452		// write session name
453		out.write("<SESSION name=\"");
454		out.write(name);
455		out.write("\">");
456		out.newLine();
457		// write files
458		out.write("  <FILES>");
459		out.newLine();
460		saveFiles(out);
461		out.write("  </FILES>");
462		out.newLine();
463		out.newLine();
464		// write properties
465		out.write("  <PROPERTIES>");
466		out.newLine();
467		saveProperties(out);
468		out.write("  </PROPERTIES>");
469		out.newLine();
470		out.write("</SESSION>");
471		out.newLine();
472		out.close();
473	}
474
475
476	private void saveFiles(BufferedWriter out) throws IOException
477	{
478		Enumeration myEnum = sessionFiles.elements();
479		while(myEnum.hasMoreElements())
480		{
481			SessionFile sf = (SessionFile)myEnum.nextElement();
482			String filename = sf.getPath().replace('\\','/');
483			out.write("      <FILE filename=\"");
484			out.write(ParseUtilities.encodeXML(filename));
485			out.write('"');
486			if(filename.equals(getCurrentFile().replace('\\','/')))
487				out.write(" isCurrent=\"true\"");
488			// Write character encoding info, carat position
489			Buffer buff = jEdit.getBuffer(filename);
490			if (buff != null)
491			{
492				String encoding = buff.getStringProperty(Buffer.ENCODING);
493				if (encoding != null && encoding.length() > 0)
494					out.write(" encoding=\"" + encoding + "\"");
495				Integer carat = new Integer(buff.getIntegerProperty(
496					Buffer.CARET, 0));
497				out.write(" carat=\"" + carat.toString() + "\"");
498			}
499			out.write("/>");
500			out.newLine();
501		}
502	}
503
504
505	private void saveProperties(BufferedWriter out) throws IOException
506	{
507		Enumeration myEnum = properties.keys();
508		while(myEnum.hasMoreElements())
509		{
510			String key = myEnum.nextElement().toString();
511			String value = getProperty(key);
512			Log.log(Log.DEBUG, this, "Writing PROP: " + key);
513			out.write("      <PROP key=\"");
514			out.write(ParseUtilities.encodeXML(key));
515			out.write('"');
516			// if value is null, don't write a value="" element:
517			if(value != null)
518			{
519				out.write(" value=\"");
520				out.write(ParseUtilities.encodeXML(value));
521				out.write('"');
522			}
523			out.write("/>");
524			out.newLine();
525		}
526	}
527
528
529	private class SessionXmlHandler extends DefaultHandler
530	{
531		boolean atStart = false;
532		SessionXmlHandler()
533		{
534		}
535
536		public void startDocument() throws SAXException
537		{
538			super.startDocument();
539			atStart = true;
540		}
541
542		public void startElement(String uri, String localName, String name, Attributes attributes)
543			throws SAXException
544		{
545			if (atStart)
546			{
547				if (localName.equalsIgnoreCase("session"))
548				{
549					atStart = false;
550					return;
551				}
552				else
553				{
554					throw new SAXException("DOCTYPE must be SESSION");
555				}
556			}
557			if (name.equalsIgnoreCase("prop"))
558			{
559				String key = attributes.getValue("key");
560				String value = attributes.getValue("value");
561				properties.put(key, value);
562			}
563			else if (name.equalsIgnoreCase("file"))
564			{
565				String filePath = attributes.getValue("filename");
566				String encoding = attributes.getValue("encoding");
567				boolean isCurrent = "true".equalsIgnoreCase(attributes.getValue("isCurrent"));
568				addFile(filePath, encoding);
569				if (isCurrent)
570				{
571					setCurrentFile(filePath);
572				}
573			}
574			super.startElement(uri, localName, name, attributes);
575		}
576
577		public InputSource resolveEntity(String publicId, String systemId) throws IOException
578		{
579			if (systemId.endsWith("session.dtd"))
580				return new InputSource(new BufferedReader(new InputStreamReader(this.getClass()
581					.getResourceAsStream("session.dtd"))));
582			return null;
583		}
584	}
585}