/**
* 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.editor.xml;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.texteditor.IDocumentProvider;
import com.aptana.ide.editor.xml.XMLDocumentProvider.XMLFileInfo;
import com.aptana.ide.editor.xml.lexing.XMLTokenTypes;
import com.aptana.ide.editor.xml.parsing.XMLMimeType;
import com.aptana.ide.editor.xml.preferences.IPreferenceConstants;
import com.aptana.ide.editors.toolbar.ToolbarWidget;
import com.aptana.ide.editors.unified.DocumentSourceProvider;
import com.aptana.ide.editors.unified.IFileServiceFactory;
import com.aptana.ide.editors.unified.IUnifiedEditorContributor;
import com.aptana.ide.editors.unified.UnifiedEditor;
import com.aptana.ide.lexer.IToken;
import com.aptana.ide.lexer.Lexeme;
import com.aptana.ide.lexer.LexemeList;
/**
* @author Robin Debreuil
*/
public class XMLEditor extends UnifiedEditor
{
private boolean isDisposing = false;
private boolean _isMarkingBothTags;
/**
* XMLEditor
*/
public XMLEditor()
{
super();
addPluginToPreferenceStore(XMLPlugin.getDefault());
_isMarkingBothTags = getPreferenceStore().getBoolean(IPreferenceConstants.XMLEDITOR_HIGHLIGHT_START_END_TAGS);
}
/**
* @see com.aptana.ide.editors.unified.UnifiedEditor#createLocalContributor()
*/
protected IUnifiedEditorContributor createLocalContributor()
{
return new XMLContributor();
}
/**
* @see com.aptana.ide.editors.unified.UnifiedEditor#getFileServiceFactory()
*/
public IFileServiceFactory getFileServiceFactory()
{
return XMLFileServiceFactory.getInstance();
}
/**
* @see com.aptana.ide.editors.unified.UnifiedEditor#getDefaultFileExtension()
*/
public String getDefaultFileExtension()
{
return "xml"; //$NON-NLS-1$
}
/**
* @see org.eclipse.ui.IWorkbenchPart#dispose()
*/
public void dispose()
{
if(isDisposing)
{
return;
}
isDisposing = true;
super.dispose();
}
/**
* isNewInput
*
* @param input
* @return boolean
*/
protected boolean isNewInput( IEditorInput input )
{
XMLFileInfo cuInfo = getXMLFileInfo( input );
if ( cuInfo == null )
{
throw new RuntimeException( Messages.XMLEditor_cuInfo_Null_At_DoSetInput );
}
XMLDocumentProvider dp = (XMLDocumentProvider) getDocumentProvider( );
// Get document from input
IDocument document = dp.getDocument( input );
DocumentSourceProvider provider = new DocumentSourceProvider( document,
input );
if ( provider == null )
{
throw new RuntimeException( Messages.XMLEditor_Provider_Null );
}
return ( cuInfo.sourceProvider == null || cuInfo.sourceProvider.equals( provider ) == false );
}
private XMLFileInfo getXMLFileInfo( IEditorInput input )
{
XMLDocumentProvider dp = (XMLDocumentProvider) getDocumentProvider( );
if ( dp == null )
{
throw new RuntimeException( Messages.XMLEditor_Document_Provider_Null );
}
return (XMLFileInfo) dp.getFileInfoPublic( input );
}
/**
* Updates the file information
*
* @param input
* @param provider
* @param document
*/
protected void updateFileInfo( IEditorInput input,
DocumentSourceProvider provider, IDocument document)
{
super.updateFileInfo( input, provider, document );
if ( isNewInput(input))
{
// save reference to provider
getXMLFileInfo( input ).sourceProvider = provider;
}
}
private ToolbarWidget toolbar;
private Composite displayArea;
/**
* @see com.aptana.ide.editors.unified.UnifiedEditor#createPartControl(org.eclipse.swt.widgets.Composite)
*/
public void createPartControl(Composite parent)
{
displayArea = new Composite(parent, SWT.NONE);
GridLayout daLayout = new GridLayout(1, true);
daLayout.marginHeight = 0;
daLayout.marginWidth = 0;
displayArea.setLayout(daLayout);
displayArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
boolean show = getPreferenceStore().getBoolean(IPreferenceConstants.SHOW_XML_TOOLBAR);
if (show)
{
toolbar = new ToolbarWidget(new String[] { XMLMimeType.MimeType }, new String[] { "XML" }, //$NON-NLS-1$
getPreferenceStore(), IPreferenceConstants.SHOW_XML_TOOLBAR, this);
toolbar.createControl(displayArea);
}
Composite editorArea = new Composite(displayArea, SWT.NONE);
editorArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
GridLayout eaLayout = new GridLayout(1, true);
eaLayout.marginHeight = 0;
eaLayout.marginWidth = 0;
editorArea.setLayout(new FillLayout());
super.createPartControl(editorArea);
}
/**
* Can this lexeme be highlighted for matching occurrences ?
*
* @param lexeme
* @return true if this token type is eligible for occurrence marking
*/
public boolean canMarkOccurrences(Lexeme lexeme)
{
IToken token = lexeme.getToken();
int typeIndex = token.getTypeIndex();
if(typeIndex == XMLTokenTypes.WHITESPACE || typeIndex == XMLTokenTypes.COMMENT || typeIndex == XMLTokenTypes.TEXT )
{
return false;
}
return true;
}
/**
* Overridden parent method to handle highlighting of both start and end tag when either is selected
*
* If/when we have common based class for tag based languages (html, xml etc.), this method should be moved there.
*
* @see com.aptana.ide.editors.unified.UnifiedEditor#markOccurences(com.aptana.ide.lexer.LexemeList, com.aptana.ide.lexer.Lexeme)
*/
protected void markOccurences(LexemeList lexemeList, Lexeme selectedLexeme)
{
boolean deferToParent = true;
if(_isMarkingBothTags && ( selectedLexeme.typeIndex == XMLTokenTypes.START_TAG || selectedLexeme.typeIndex == XMLTokenTypes.END_TAG ) )
{
deferToParent = false;
String selectedText = selectedLexeme.getText();
String normalizedSelectedText = selectedText;
// convert e.g. "</table" to <table"
if(selectedLexeme.typeIndex == XMLTokenTypes.END_TAG)
{
if(selectedLexeme.length >=3)
{
normalizedSelectedText = selectedText.substring(0,1) + selectedText.substring(2);
}
}
for (int i = 0; i < lexemeList.size(); i++)
{
Lexeme lexeme = lexemeList.get(i);
if (lexeme != null)
{
if (lexeme.isHighlighted())
{
lexeme.setHighlighted(false);
}
if (lexeme.typeIndex == XMLTokenTypes.START_TAG || lexeme.typeIndex == XMLTokenTypes.END_TAG)
{
if( lexeme.typeIndex == selectedLexeme.typeIndex && lexeme.length == selectedLexeme.length)
{
if(selectedText.equals(lexeme.getText()))
{
lexeme.setHighlighted(true);
}
}
else if( (lexeme.length - selectedLexeme.length) == 1)
{
if(lexeme.typeIndex == XMLTokenTypes.END_TAG)
{
if(lexeme.length >=3)
{
String normalizedText = lexeme.getText().substring(0,1) + lexeme.getText().substring(2);
if(normalizedText.equals(selectedText))
{
lexeme.setHighlighted(true);
}
}
}
}
else if( (selectedLexeme.length - lexeme.length) == 1)
{
if(normalizedSelectedText.equals(lexeme.getText()))
{
lexeme.setHighlighted(true);
}
}
}
}
}
}
if(deferToParent)
{
super.markOccurences(lexemeList, selectedLexeme);
}
}
/**
* @see com.aptana.ide.editors.unified.UnifiedEditor#createDocumentProvider()
*/
public IDocumentProvider createDocumentProvider()
{
return XMLDocumentProvider.getInstance();
}
/**
* @see org.eclipse.ui.texteditor.AbstractDecoratedTextEditor#collectContextMenuPreferencePages()
*/
protected String[] collectContextMenuPreferencePages()
{
return new String[] {
"com.aptana.ide.editor.xml.preferences.GeneralPreferencePage", //$NON-NLS-1$
"com.aptana.ide.editor.xml.preferences.ColorizationPreferencePage", //$NON-NLS-1$
"com.aptana.ide.editor.xml.preferences.FoldingPreferencePage", //$NON-NLS-1$
"com.aptana.ide.editor.xml.preferences.ProblemsPreferencePage", //$NON-NLS-1$
"com.aptana.ide.editor.xml.preferences.FormattingPreferencePage", //$NON-NLS-1$
"com.aptana.ide.editor.xml.preferences.CodeAssistPreferencePage", //$NON-NLS-1$
"com.aptana.ide.editor.xml.preferences.TypingPreferencePage", //$NON-NLS-1$
"org.eclipse.ui.preferencePages.GeneralTextEditor", //$NON-NLS-1$
"org.eclipse.ui.editors.preferencePages.Annotations", //$NON-NLS-1$
"org.eclipse.ui.editors.preferencePages.QuickDiff", //$NON-NLS-1$
"org.eclipse.ui.editors.preferencePages.Accessibility", //$NON-NLS-1$
"org.eclipse.ui.editors.preferencePages.Spelling", //$NON-NLS-1$
"org.eclipse.ui.editors.preferencePages.LinkedModePreferencePage", //$NON-NLS-1$
};
}
/**
* @see com.aptana.ide.editors.unified.UnifiedEditor#handlePreferenceStoreChanged(org.eclipse.jface.util.PropertyChangeEvent)
*/
protected void handlePreferenceStoreChanged(PropertyChangeEvent event)
{
String property = event.getProperty();
if (IPreferenceConstants.XMLEDITOR_HIGHLIGHT_START_END_TAGS.equals(property))
{
_isMarkingBothTags = getPreferenceStore().getBoolean(IPreferenceConstants.XMLEDITOR_HIGHLIGHT_START_END_TAGS);
}
else
{
super.handlePreferenceStoreChanged(event);
}
}
}