/**
* This file Copyright (c) 2005-2008 Aptana, Inc. This program is
* dual-licensed under both the Aptana Public License and the GNU General
* Public license. You may elect to use one or the other of these licenses.
*
* This program is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. Redistribution, except as permitted by whichever of
* the GPL or APL you select, is prohibited.
*
* 1. For the GPL license (GPL), you can redistribute and/or modify this
* program under the terms of the GNU General Public License,
* Version 3, as published by the Free Software Foundation. You should
* have received a copy of the GNU General Public License, Version 3 along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Aptana provides a special exception to allow redistribution of this file
* with certain other free and open source software ("FOSS") code and certain additional terms
* pursuant to Section 7 of the GPL. You may view the exception and these
* terms on the web at http://www.aptana.com/legal/gpl/.
*
* 2. For the Aptana Public License (APL), this program and the
* accompanying materials are made available under the terms of the APL
* v1.0 which accompanies this distribution, and is available at
* http://www.aptana.com/legal/apl/.
*
* You may view the GPL, Aptana's exception and additional terms, and the
* APL in the file titled license.html at the root of the corresponding
* plugin containing this source file.
*
* Any modifications to this file must keep this entire header intact.
*/
package com.aptana.ide.snippets;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.eclipse.ui.texteditor.ITextEditor;
import com.aptana.ide.core.FileUtils;
import com.aptana.ide.editors.toolbar.IToolBarMember;
import com.aptana.ide.editors.toolbar.ToolBarContribution;
import com.aptana.ide.editors.toolbar.ToolBarContributionRegistry;
import com.aptana.ide.editors.unified.IUnifiedEditor;
/**
* @author Kevin Lindsey
* @author Pavel Petrochenko
*/
public final class SnippetsManager
{
/**
* @author Pavel Petrochenko
*/
public class SnippetNode
{
private String categoryName;
private Map<String,SnippetNode> categoryMap = new HashMap<String,SnippetNode>();
private List<Snippet> childNodes = new ArrayList<Snippet>();
/**
* @param name
*/
public SnippetNode(String name)
{
this.categoryName = name;
}
/**
* @return category name
*/
public String getCategoryName()
{
return categoryName;
}
/**
* @return true
*/
public boolean hasChilds()
{
return !(categoryMap.isEmpty() && childNodes.isEmpty());
}
/**
* @return sub categories
*/
public SnippetNode[] getSubCategories()
{
Collection<SnippetNode> values = categoryMap.values();
return values.toArray(new SnippetNode[values.size()]);
}
/**
* @return All children, categories first
*/
public Object[] getAllChildren()
{
List<SnippetNode> lst = new ArrayList<SnippetNode>(categoryMap.values());
Collections.sort(lst, new Comparator<SnippetNode>()
{
public int compare(SnippetNode n0, SnippetNode n1)
{
return n0.getCategoryName().compareTo(n1.getCategoryName());
}
});
List<Snippet> arrayList = new ArrayList<Snippet>(childNodes);
Collections.sort(arrayList, new Comparator<Snippet>()
{
public int compare(Snippet n0, Snippet n1)
{
return n0.getName().compareTo(n1.getName());
}
});
List<Object> result = new ArrayList<Object>();
result.addAll(lst);
result.addAll(arrayList);
return result.toArray();
}
/**
* @return Snippets
*/
public Snippet[] getChildren()
{
Snippet[] children = new Snippet[childNodes.size()];
childNodes.toArray(children);
return children;
}
/**
* @param path
* @param position
* @param snippet
*/
public void add(String[] path, int position, Snippet snippet)
{
if (position == path.length)
{
childNodes.add(snippet);
return;
}
String string = path[position].trim();
SnippetNode object = categoryMap.get(string);
if (object == null)
{
object = new SnippetNode(string);
categoryMap.put(string, object);
}
object.add(path, position + 1, snippet);
}
/**
* @param path
* @param position
* @param snippet
*/
public void remove(String[] path, int position, Snippet snippet)
{
if (position == path.length)
{
if (childNodes.remove(snippet))
{
fireChangeListeners();
}
}
else
{
String string = path[position].trim();
SnippetNode object = categoryMap.get(string);
if (object != null)
{
object.remove(path, position + 1, snippet);
if (object.childNodes.isEmpty())
{
categoryMap.remove(string);
fireChangeListeners();
}
}
}
}
}
private static final Snippet[] NO_SNIPPETS = null;
private static SnippetsManager instance;
private Map<Snippet,ToolBarContribution> _tContributions = new HashMap<Snippet,ToolBarContribution>();
private SnippetNode _rootNode = new SnippetNode(""); //$NON-NLS-1$
private List<SnippetListChangeListener> _snippetListChangeListeners;
private Map<File,Snippet> _snippetsByFile;
private Map<String,List<Snippet>> _snippetsByCategory;
private String _tempDirectory;
/**
* SnippetsList
*/
private SnippetsManager()
{
this._snippetsByFile = new HashMap<File,Snippet>();
this._snippetsByCategory = new HashMap<String, List<Snippet>>();
Path p = new Path(FileUtils.systemTempDir);
this._tempDirectory = p.append("aptana/snippets").toOSString(); //$NON-NLS-1$
File f = new File(this._tempDirectory);
f.mkdir();
}
/**
* getInstance
*
* @return SnippetsList instance
*/
public static SnippetsManager getInstance()
{
if (instance == null)
{
instance = new SnippetsManager();
}
return instance;
}
/**
* addChangeListener
*
* @param listener
*/
public void addChangeListener(SnippetListChangeListener listener)
{
if (listener != null)
{
if (this._snippetListChangeListeners == null)
{
this._snippetListChangeListeners = new ArrayList<SnippetListChangeListener>();
}
this._snippetListChangeListeners.add(listener);
}
}
/**
* fireChangeListeners
*/
public void fireChangeListeners()
{
if (this._snippetListChangeListeners != null)
{
for (int i = 0; i < this._snippetListChangeListeners.size(); i++)
{
this._snippetListChangeListeners.get(i).listChanged(this);
}
}
}
/**
* removeChangeListener
*
* @param listener
*/
public void removeChangeListener(SnippetListChangeListener listener)
{
if (listener != null)
{
if (this._snippetListChangeListeners != null)
{
this._snippetListChangeListeners.remove(listener);
}
}
}
/**
* addSnippet
*
* @param category
* @param name
* @param content
*/
public void addSnippet(String category, String name, String content)
{
this.addSnippet(new Snippet(category, name, content));
}
/**
* addSnippet
*
* @param snippet
*/
public void addSnippet(final Snippet snippet)
{
if (snippet == null)
{
throw new IllegalArgumentException(Messages.SnippetsManager_Snippet_Undefined);
}
// get snippet category
String category = snippet.getCategory();
// add to category list
if (this._snippetsByCategory.containsKey(category) == false)
{
this._snippetsByCategory.put(category, new ArrayList<Snippet>());
}
this._snippetsByCategory.get(category).add(snippet);
// add to model
String[] path = getCategoryPath(category);
this._rootNode.add(path, 0, snippet);
// add a snippet lookup by file, if a file associate exists
File file = snippet.getFile();
if (file != null)
{
this._snippetsByFile.put(file, snippet);
}
if (snippet.isToolbar())
{
String icon = snippet.getIcon();
ImageDescriptor imageDescriptor = null;
if (icon!= null && icon.length() != 0)
{
int indexOf = icon.indexOf('/');
String bundle = icon.substring(0, indexOf);
String imagePath = icon.substring(indexOf);
imageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(bundle, imagePath);
}
else
{
imageDescriptor = SnippetsPlugin.getImageDescriptor("/icons/snippet.png");//$NON-NLS-1$
}
ToolBarContribution toolBarContribution = new ToolBarContribution(
snippet.getName(),
snippet.getTooltip(),
imageDescriptor, new IToolBarMember()
{
public void execute(IUnifiedEditor editor, String string)
{
if (editor instanceof ITextEditor)
{
snippet.apply((ITextEditor) editor);
}
}
});
ToolBarContributionRegistry.getInstance().addContribution(snippet.getLanguage(), toolBarContribution);
this._tContributions.put(snippet, toolBarContribution);
}
// fire change event
this.fireChangeListeners();
}
/**
* getCategoryPath
*
* @param key
* @return
*/
private String[] getCategoryPath(String key)
{
return key.split("->"); //$NON-NLS-1$
}
/**
* getSnippetsByCategory
*
* @return Snippet[]
*/
public Snippet[] getSnippetsByCategory(String category)
{
Snippet[] result = NO_SNIPPETS;
if (this._snippetsByCategory.containsKey(category))
{
List<Snippet> snippets = this._snippetsByCategory.get(category);
result = snippets.toArray(new Snippet[snippets.size()]);
}
return result;
}
/**
* getSnippetByFile
*
* @param file
* @return Snippet or null
*/
public Snippet getSnippetByFile(File file)
{
Snippet result = null;
if (this._snippetsByFile.containsKey(file))
{
result = this._snippetsByFile.get(file);
}
return result;
}
/**
* loadSnippetDirectory
*
* @param snippetsDirectory
*/
public void loadSnippetDirectory(File snippetsDirectory)
{
// get all files in snippets directory
File[] files = snippetsDirectory.listFiles();
if (files == null)
{
return;
}
// process each snippet file
for (int i = 0; i < files.length; i++)
{
File file = files[i];
if (file.isFile())
{
Snippet snippet = Snippet.fromFile(file);
if (snippet != null)
{
this.addSnippet(snippet);
}
}
}
}
/**
* removeSnippet
*
* @param snippet
*/
public void removeSnippet(Snippet snippet)
{
if (snippet != null)
{
// get snippet category
String category = snippet.getCategory();
// remove from category list
if (this._snippetsByCategory.containsKey(category))
{
List<Snippet> snippets = this._snippetsByCategory.get(category);
snippets.remove(snippet);
if (snippets.size() == 0)
{
this._snippetsByCategory.remove(category);
}
}
// remove from model
String[] path = getCategoryPath(category);
this._rootNode.remove(path, 0, snippet);
// remove file association
File file = snippet.getFile();
if (file != null)
{
this._snippetsByFile.remove(file);
}
ToolBarContribution contribution = this._tContributions.get(snippet);
if (contribution != null)
{
this._tContributions.remove(snippet);
ToolBarContributionRegistry.getInstance().removeContribution(snippet.getLanguage(),contribution);
}
}
}
/**
* @return root node
*/
public SnippetNode getRootNode()
{
return this._rootNode;
}
/**
* The temporary directory for storing snippets
*
* @return - temp snippet directory
*/
public String getSnippetTempDirectory()
{
return this._tempDirectory;
}
}