/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ package org.apache.directory.studio.ldifeditor.editor.reconciler; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.directory.studio.ldifeditor.LdifEditorActivator; import org.apache.directory.studio.ldifeditor.LdifEditorConstants; import org.apache.directory.studio.ldifeditor.editor.ILdifEditor; import org.apache.directory.studio.ldifparser.model.LdifFile; import org.apache.directory.studio.ldifparser.model.LdifPart; import org.apache.directory.studio.ldifparser.model.container.LdifCommentContainer; import org.apache.directory.studio.ldifparser.model.container.LdifContainer; import org.apache.directory.studio.ldifparser.model.lines.LdifNonEmptyLineBase; import org.apache.directory.studio.ldifparser.model.lines.LdifSepLine; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.text.source.projection.ProjectionAnnotation; import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; public class LdifFoldingRegionUpdater implements IPropertyChangeListener { private ILdifEditor editor; public LdifFoldingRegionUpdater( ILdifEditor editor ) { this.editor = editor; LdifEditorActivator.getDefault().getPreferenceStore().addPropertyChangeListener( this ); } public void dispose() { LdifEditorActivator.getDefault().getPreferenceStore().removePropertyChangeListener( this ); } public void propertyChange( PropertyChangeEvent event ) { if ( LdifEditorConstants.PREFERENCE_LDIFEDITOR_FOLDING_ENABLE.equals( event.getProperty() ) || LdifEditorConstants.PREFERENCE_LDIFEDITOR_FOLDING_INITIALLYFOLDCOMMENTS.equals( event.getProperty() ) || LdifEditorConstants.PREFERENCE_LDIFEDITOR_FOLDING_INITIALLYFOLDRECORDS.equals( event.getProperty() ) || LdifEditorConstants.PREFERENCE_LDIFEDITOR_FOLDING_INITIALLYFOLDWRAPPEDLINES.equals( event.getProperty() ) ) { this.updateFoldingRegions(); } } public void updateFoldingRegions() { ISourceViewer viewer = ( ISourceViewer ) editor.getAdapter( ISourceViewer.class ); if ( viewer == null ) return; IDocument document = viewer.getDocument(); try { ProjectionAnnotationModel projectionAnnotationModel = ( ProjectionAnnotationModel ) editor .getAdapter( ProjectionAnnotationModel.class ); if ( projectionAnnotationModel == null ) return; // create folding regions of current LDIF model; mark comments // and // folded lines as collapsed Map<Position, ProjectionAnnotation> positionToAnnotationMap = createFoldingRegions( editor.getLdifModel(), document ); // compare with current annotation model (--> toAdd, toDelete) List<Annotation> annotationsToDeleteList = new ArrayList<Annotation>(); Map<ProjectionAnnotation, Position> annotationsToAddMap = new HashMap<ProjectionAnnotation, Position>(); this.computeDifferences( projectionAnnotationModel, positionToAnnotationMap, annotationsToDeleteList, annotationsToAddMap ); Annotation[] annotationsToDelete = ( Annotation[] ) annotationsToDeleteList .toArray( new Annotation[annotationsToDeleteList.size()] ); // update annotation model if ( !annotationsToDeleteList.isEmpty() || !annotationsToAddMap.isEmpty() ) { projectionAnnotationModel.modifyAnnotations( annotationsToDelete, annotationsToAddMap, new Annotation[0] ); } } catch ( BadLocationException e ) { e.printStackTrace(); } } private void computeDifferences( ProjectionAnnotationModel model, Map<Position, ProjectionAnnotation> positionToAnnotationMap, List<Annotation> annotationsToDeleteList, Map<ProjectionAnnotation, Position> annotationsToAddMap ) { for ( Iterator<Annotation> iter = model.getAnnotationIterator(); iter.hasNext(); ) { Annotation annotation = iter.next(); if ( annotation instanceof ProjectionAnnotation ) { Position position = model.getPosition( ( Annotation ) annotation ); if ( positionToAnnotationMap.containsKey( position ) ) { positionToAnnotationMap.remove( position ); } else { annotationsToDeleteList.add( annotation ); } } } for ( Map.Entry<Position, ProjectionAnnotation> entry : positionToAnnotationMap.entrySet() ) { annotationsToAddMap.put( entry.getValue(), entry.getKey() ); } } /** * Creates all folding region of the given LDIF model. * LdifCommentContainers and wrapped lines are marked as collapsed. * * @param model * @param document * @return a map with positions as keys to annotations as values * @throws BadLocationException */ private Map<Position, ProjectionAnnotation> createFoldingRegions( LdifFile model, IDocument document ) throws BadLocationException { Map<Position, ProjectionAnnotation> positionToAnnotationMap = new HashMap<Position, ProjectionAnnotation>(); List<LdifContainer> containers = model.getContainers(); boolean ENABLE_FOLDING = LdifEditorActivator.getDefault().getPreferenceStore().getBoolean( LdifEditorConstants.PREFERENCE_LDIFEDITOR_FOLDING_ENABLE ); boolean FOLD_COMMENTS = LdifEditorActivator.getDefault().getPreferenceStore().getBoolean( LdifEditorConstants.PREFERENCE_LDIFEDITOR_FOLDING_INITIALLYFOLDCOMMENTS ); boolean FOLD_RECORDS = LdifEditorActivator.getDefault().getPreferenceStore().getBoolean( LdifEditorConstants.PREFERENCE_LDIFEDITOR_FOLDING_INITIALLYFOLDRECORDS ); boolean FOLD_WRAPPEDLINES = LdifEditorActivator.getDefault().getPreferenceStore().getBoolean( LdifEditorConstants.PREFERENCE_LDIFEDITOR_FOLDING_INITIALLYFOLDWRAPPEDLINES ); if ( ENABLE_FOLDING ) { for ( LdifContainer ldifContainer : containers ) { int containerStartLine = document.getLineOfOffset( ldifContainer.getOffset() ); int containerEndLine = -1; LdifPart[] parts = ldifContainer.getParts(); for ( int j = parts.length - 1; j >= 0; j-- ) { if ( containerEndLine == -1 && ( !( parts[j] instanceof LdifSepLine ) || ( ldifContainer instanceof LdifCommentContainer && j < parts.length - 1 ) ) ) { containerEndLine = document.getLineOfOffset( parts[j].getOffset() + parts[j].getLength() - 1 ); // break; } if ( parts[j] instanceof LdifNonEmptyLineBase ) { LdifNonEmptyLineBase line = ( LdifNonEmptyLineBase ) parts[j]; if ( line.isFolded() ) { Position position = new Position( line.getOffset(), line.getLength() ); // ProjectionAnnotation annotation = new // ProjectionAnnotation(true); ProjectionAnnotation annotation = new ProjectionAnnotation( FOLD_WRAPPEDLINES ); positionToAnnotationMap.put( position, annotation ); } } } if ( containerStartLine < containerEndLine ) { int start = document.getLineOffset( containerStartLine ); int end = document.getLineOffset( containerEndLine ) + document.getLineLength( containerEndLine ); Position position = new Position( start, end - start ); ProjectionAnnotation annotation = new ProjectionAnnotation( FOLD_RECORDS || ( FOLD_COMMENTS && ldifContainer instanceof LdifCommentContainer ) ); positionToAnnotationMap.put( position, annotation ); } } } return positionToAnnotationMap; } }