package tk.eclipse.plugin.csseditor.editors;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewerExtension2;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
import org.eclipse.jface.text.source.MatchingCharacterPainter;
import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
import org.eclipse.jface.text.source.projection.ProjectionSupport;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
import org.eclipse.ui.texteditor.ChainedPreferenceStore;
import org.eclipse.ui.texteditor.ContentAssistAction;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import tk.eclipse.plugin.htmleditor.ColorProvider;
import tk.eclipse.plugin.htmleditor.HTMLPlugin;
import tk.eclipse.plugin.htmleditor.editors.FoldingInfo;
import tk.eclipse.plugin.htmleditor.editors.SoftTabVerifyListener;
/**
* CSS Editor
*
* @author Naoki Takezoe
*/
public class CSSEditor extends TextEditor {
private ColorProvider colorProvider;
private CSSOutlinePage outline;
private CSSCharacterPairMatcher pairMatcher;
private SoftTabVerifyListener softTabListener;
private ProjectionSupport fProjectionSupport;
public static final String GROUP_CSS = "_css";
public static final String ACTION_CHOOSE_COLOR = "_choose_color";
public CSSEditor() {
super();
colorProvider = HTMLPlugin.getDefault().getColorProvider();
setSourceViewerConfiguration(new CSSConfiguration(colorProvider));
setPreferenceStore(new ChainedPreferenceStore(new IPreferenceStore[] { getPreferenceStore(), HTMLPlugin.getDefault().getPreferenceStore() }));
outline = new CSSOutlinePage(this);
setAction(ACTION_CHOOSE_COLOR, new ChooseColorAction(this));
IPreferenceStore store = HTMLPlugin.getDefault().getPreferenceStore();
softTabListener = new SoftTabVerifyListener();
softTabListener.setUseSoftTab(store.getBoolean(HTMLPlugin.PREF_USE_SOFTTAB));
softTabListener.setSoftTabWidth(store.getInt(HTMLPlugin.PREF_SOFTTAB_WIDTH));
}
@Override
protected final void editorContextMenuAboutToShow(IMenuManager menu) {
super.editorContextMenuAboutToShow(menu);
menu.add(new Separator(GROUP_CSS));
addAction(menu, GROUP_CSS, ACTION_CHOOSE_COLOR);
}
@Override
protected void doSetInput(IEditorInput input) throws CoreException {
if (input instanceof IFileEditorInput) {
setDocumentProvider(new CSSTextDocumentProvider());
}
else if (input instanceof IStorageEditorInput) {
setDocumentProvider(new CSSFileDocumentProvider());
}
else {
setDocumentProvider(new CSSTextDocumentProvider());
}
super.doSetInput(input);
}
@Override
public void doSave(IProgressMonitor progressMonitor) {
super.doSave(progressMonitor);
outline.update();
updateFolding();
}
@Override
protected ISourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, int styles) {
ISourceViewer viewer = new ProjectionViewer(parent, ruler, getOverviewRuler(), true, styles);
getSourceViewerDecorationSupport(viewer);
viewer.getTextWidget().addVerifyListener(softTabListener);
return viewer;
}
@Override
public void createPartControl(Composite parent) {
super.createPartControl(parent);
ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
fProjectionSupport = new ProjectionSupport(viewer, getAnnotationAccess(), getSharedColors());
fProjectionSupport.install();
viewer.doOperation(ProjectionViewer.TOGGLE);
updateFolding();
StyledText widget = viewer.getTextWidget();
widget.setTabs(getPreferenceStore().getInt(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_TAB_WIDTH));
widget.addVerifyListener(new SoftTabVerifyListener());
ITextViewerExtension2 extension = (ITextViewerExtension2) getSourceViewer();
pairMatcher = new CSSCharacterPairMatcher();
pairMatcher.setEnable(getPreferenceStore().getBoolean(HTMLPlugin.PREF_PAIR_CHAR));
MatchingCharacterPainter painter = new MatchingCharacterPainter(getSourceViewer(), pairMatcher);
painter.setColor(Display.getDefault().getSystemColor(SWT.COLOR_GRAY));
extension.addPainter(painter);
}
@Override
public void dispose() {
pairMatcher.dispose();
fProjectionSupport.dispose();
super.dispose();
}
@Override
public void doSaveAs() {
super.doSaveAs();
outline.update();
updateFolding();
}
@Override
protected boolean affectsTextPresentation(PropertyChangeEvent event) {
return super.affectsTextPresentation(event) || colorProvider.affectsTextPresentation(event);
}
@Override
protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
colorProvider.handlePreferenceStoreChanged(event);
String key = event.getProperty();
if (key.equals(HTMLPlugin.PREF_PAIR_CHAR)) {
boolean enable = ((Boolean) event.getNewValue()).booleanValue();
pairMatcher.setEnable(enable);
}
super.handlePreferenceStoreChanged(event);
softTabListener.preferenceChanged(event);
}
@Override
protected void createActions() {
super.createActions();
// Add a content assist action
IAction action = new ContentAssistAction(HTMLPlugin.getDefault().getResourceBundle(), "ContentAssistProposal", this);
action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
setAction("ContentAssistProposal", action);
}
@Override
public Object getAdapter(Class adapter) {
if (IContentOutlinePage.class.equals(adapter)) {
return outline;
}
if (ProjectionAnnotationModel.class.equals(adapter) && fProjectionSupport != null) {
Object obj = fProjectionSupport.getAdapter(getSourceViewer(), adapter);
if (obj != null) {
return obj;
}
}
return super.getAdapter(adapter);
}
private static final int FOLDING_NONE = 0;
private static final int FOLDING_STYLE = 1;
private static final int FOLDING_COMMENT = 2;
/**
* Update folding informations.
*/
private void updateFolding() {
try {
ProjectionViewer viewer = (ProjectionViewer) getSourceViewer();
if (viewer == null) {
return;
}
ProjectionAnnotationModel model = viewer.getProjectionAnnotationModel();
if (model == null) {
return;
}
List<FoldingInfo> list = new ArrayList<FoldingInfo>();
IDocument doc = getDocumentProvider().getDocument(getEditorInput());
String source = doc.get();
int type = FOLDING_NONE;
int start = -1;
int startBackup = -1;
for (int i = 0; i < source.length(); i++) {
char c = source.charAt(i);
// start comment
if (c == '/' && type != FOLDING_COMMENT && source.length() > i + 1) {
if (source.charAt(i + 1) == '*') {
if (type == FOLDING_STYLE) {
startBackup = start;
}
type = FOLDING_COMMENT;
start = i;
i++;
}
// end comment
}
else if (c == '*' && type == FOLDING_COMMENT && source.length() > i + 1) {
if (source.charAt(i + 1) == '/') {
if (doc.getLineOfOffset(start) != doc.getLineOfOffset(i)) {
list.add(new FoldingInfo(start, i + 2 + FoldingInfo.countUpLineDelimiter(source, i + 2)));
}
if (startBackup != -1) {
type = FOLDING_STYLE;
start = startBackup;
}
else {
type = FOLDING_NONE;
}
startBackup = -1;
i++;
}
// start blace
}
else if (c == '{' && type == FOLDING_NONE) {
if (type == FOLDING_COMMENT) {
startBackup = start;
}
start = i;
type = FOLDING_STYLE;
// end blace
}
else if (type == FOLDING_STYLE && c == '}') {
if (doc.getLineOfOffset(start) != doc.getLineOfOffset(i)) {
list.add(new FoldingInfo(start, i + 1 + FoldingInfo.countUpLineDelimiter(source, i + 1)));
}
if (startBackup != -1) {
type = FOLDING_COMMENT;
start = startBackup;
}
startBackup = -1;
type = FOLDING_NONE;
}
}
FoldingInfo.applyModifiedAnnotations(model, list);
}
catch (Exception ex) {
HTMLPlugin.logException(ex);
}
}
}