| /* |
| * 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.ldapbrowser.common.widgets.browser; |
| |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.directory.studio.connection.core.jobs.OpenConnectionsRunnable; |
| import org.apache.directory.studio.connection.core.jobs.StudioConnectionRunnableWithProgress; |
| import org.apache.directory.studio.ldapbrowser.core.jobs.InitializeChildrenRunnable; |
| import org.apache.directory.studio.ldapbrowser.core.jobs.SearchRunnable; |
| import org.apache.directory.studio.ldapbrowser.core.jobs.StudioBrowserJob; |
| import org.apache.directory.studio.ldapbrowser.core.model.IBookmark; |
| import org.apache.directory.studio.ldapbrowser.core.model.IBrowserConnection; |
| import org.apache.directory.studio.ldapbrowser.core.model.IContinuation; |
| import org.apache.directory.studio.ldapbrowser.core.model.IContinuation.State; |
| import org.apache.directory.studio.ldapbrowser.core.model.IEntry; |
| import org.apache.directory.studio.ldapbrowser.core.model.IQuickSearch; |
| import org.apache.directory.studio.ldapbrowser.core.model.IRootDSE; |
| import org.apache.directory.studio.ldapbrowser.core.model.ISearch; |
| import org.apache.directory.studio.ldapbrowser.core.model.ISearchResult; |
| import org.apache.directory.studio.ldapbrowser.core.model.impl.DirectoryMetadataEntry; |
| import org.apache.directory.studio.ldapbrowser.core.model.impl.SearchContinuation; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.ITreeContentProvider; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.jface.viewers.TreeViewer; |
| import org.eclipse.jface.viewers.Viewer; |
| |
| |
| /** |
| * The BrowserContentProvider implements the content provider for |
| * the browser widget. It accepts an IConnection as input. |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| public class BrowserContentProvider implements ITreeContentProvider |
| { |
| /** The viewer. */ |
| private TreeViewer viewer; |
| |
| /** The preferences */ |
| protected BrowserPreferences preferences; |
| |
| /** The sorter */ |
| protected BrowserSorter sorter; |
| |
| /** This map contains the pages for entries with many children (if folding is activated) */ |
| private Map<IEntry, BrowserEntryPage[]> entryToEntryPagesMap; |
| |
| /** This map contains the pages for searches with many results (if folding is activated) */ |
| private Map<ISearch, BrowserSearchResultPage[]> searchToSearchResultPagesMap; |
| |
| /** This map contains the top-level categories for each connection */ |
| private Map<IBrowserConnection, BrowserCategory[]> connectionToCategoriesMap; |
| |
| /** The page listener. */ |
| private ISelectionChangedListener pageListener = new ISelectionChangedListener() |
| { |
| public void selectionChanged( SelectionChangedEvent event ) |
| { |
| IStructuredSelection selection = ( IStructuredSelection ) event.getSelection(); |
| if ( selection.size() == 1 && selection.getFirstElement() instanceof StudioConnectionRunnableWithProgress ) |
| { |
| StudioConnectionRunnableWithProgress runnable = ( StudioConnectionRunnableWithProgress ) selection |
| .getFirstElement(); |
| new StudioBrowserJob( runnable ).execute(); |
| } |
| } |
| }; |
| |
| |
| /** |
| * Creates a new instance of BrowserContentProvider. |
| * |
| * @param viewer the viewer |
| * @param preferences the preferences |
| * @param sorter the sorter |
| */ |
| public BrowserContentProvider( BrowserWidget widget, BrowserPreferences preferences, BrowserSorter sorter ) |
| { |
| this.viewer = widget.getViewer(); |
| this.preferences = preferences; |
| this.sorter = sorter; |
| this.entryToEntryPagesMap = new HashMap<IEntry, BrowserEntryPage[]>(); |
| this.searchToSearchResultPagesMap = new HashMap<ISearch, BrowserSearchResultPage[]>(); |
| this.connectionToCategoriesMap = new HashMap<IBrowserConnection, BrowserCategory[]>(); |
| |
| viewer.addSelectionChangedListener( pageListener ); |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void inputChanged( Viewer v, Object oldInput, Object newInput ) |
| { |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void dispose() |
| { |
| if ( entryToEntryPagesMap != null ) |
| { |
| entryToEntryPagesMap.clear(); |
| entryToEntryPagesMap = null; |
| } |
| if ( searchToSearchResultPagesMap != null ) |
| { |
| searchToSearchResultPagesMap.clear(); |
| searchToSearchResultPagesMap = null; |
| } |
| if ( connectionToCategoriesMap != null ) |
| { |
| connectionToCategoriesMap.clear(); |
| connectionToCategoriesMap = null; |
| } |
| viewer.removeSelectionChangedListener( pageListener ); |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Object[] getElements( Object parent ) |
| { |
| if ( parent instanceof IBrowserConnection ) |
| { |
| IBrowserConnection connection = ( IBrowserConnection ) parent; |
| if ( !connectionToCategoriesMap.containsKey( connection ) ) |
| { |
| BrowserCategory[] categories = new BrowserCategory[3]; |
| categories[0] = new BrowserCategory( BrowserCategory.TYPE_DIT, connection ); |
| categories[1] = new BrowserCategory( BrowserCategory.TYPE_SEARCHES, connection ); |
| categories[2] = new BrowserCategory( BrowserCategory.TYPE_BOOKMARKS, connection ); |
| connectionToCategoriesMap.put( connection, categories ); |
| } |
| |
| BrowserCategory[] categories = connectionToCategoriesMap.get( connection ); |
| |
| List<BrowserCategory> catList = new ArrayList<BrowserCategory>( 3 ); |
| if ( preferences.isShowDIT() ) |
| { |
| catList.add( categories[0] ); |
| } |
| if ( preferences.isShowSearches() ) |
| { |
| catList.add( categories[1] ); |
| } |
| if ( preferences.isShowBookmarks() ) |
| { |
| catList.add( categories[2] ); |
| } |
| |
| return catList.toArray( new BrowserCategory[0] ); |
| } |
| else if ( parent instanceof IEntry[] ) |
| { |
| return ( IEntry[] ) parent; |
| } |
| else |
| { |
| return getChildren( parent ); |
| } |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Object getParent( final Object child ) |
| { |
| if ( child instanceof BrowserCategory ) |
| { |
| return ( ( BrowserCategory ) child ).getParent(); |
| } |
| else if ( child instanceof BrowserEntryPage ) |
| { |
| return ( ( BrowserEntryPage ) child ).getParent(); |
| } |
| else if ( child instanceof IEntry ) |
| { |
| IEntry parentEntry = ( ( IEntry ) child ).getParententry(); |
| if ( parentEntry == null ) |
| { |
| if ( connectionToCategoriesMap.get( ( ( IEntry ) child ).getBrowserConnection() ) != null ) |
| { |
| return connectionToCategoriesMap.get( ( ( IEntry ) child ).getBrowserConnection() )[0]; |
| } |
| else |
| { |
| return null; |
| } |
| } |
| else if ( parentEntry.getChildrenCount() <= preferences.getFoldingSize() || !preferences.isUseFolding() ) |
| { |
| return parentEntry; |
| } |
| else |
| { |
| BrowserEntryPage[] entryPages = getEntryPages( parentEntry ); |
| BrowserEntryPage ep = null; |
| for ( int i = 0; i < entryPages.length && ep == null; i++ ) |
| { |
| ep = entryPages[i].getParentOf( ( IEntry ) child ); |
| } |
| return ep; |
| } |
| } |
| else if ( child instanceof BrowserSearchResultPage ) |
| { |
| return ( ( BrowserSearchResultPage ) child ).getParent(); |
| } |
| else if ( child instanceof IQuickSearch ) |
| { |
| IQuickSearch quickSearch = ( ( IQuickSearch ) child ); |
| IEntry entry = quickSearch.getBrowserConnection().getEntryFromCache( quickSearch.getSearchBase() ); |
| return entry; |
| } |
| else if ( child instanceof ISearch ) |
| { |
| ISearch search = ( ( ISearch ) child ); |
| if ( connectionToCategoriesMap.get( search.getBrowserConnection() ) != null ) |
| { |
| return connectionToCategoriesMap.get( search.getBrowserConnection() )[1]; |
| } |
| else |
| { |
| return null; |
| } |
| } |
| else if ( child instanceof ISearchResult ) |
| { |
| ISearch parentSearch = ( ( ISearchResult ) child ).getSearch(); |
| |
| if ( parentSearch == null || parentSearch.getSearchResults().length <= preferences.getFoldingSize() |
| || !preferences.isUseFolding() ) |
| { |
| return parentSearch; |
| } |
| else |
| { |
| BrowserSearchResultPage[] srPages = getSearchResultPages( parentSearch ); |
| BrowserSearchResultPage srp = null; |
| for ( int i = 0; i < srPages.length && srp == null; i++ ) |
| { |
| srp = srPages[i].getParentOf( ( ISearchResult ) child ); |
| } |
| return srp; |
| } |
| } |
| else if ( child instanceof IBookmark ) |
| { |
| IBookmark bookmark = ( ( IBookmark ) child ); |
| if ( connectionToCategoriesMap.get( bookmark.getBrowserConnection() ) != null ) |
| { |
| return connectionToCategoriesMap.get( bookmark.getBrowserConnection() )[2]; |
| } |
| else |
| { |
| return null; |
| } |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Object[] getChildren( Object parent ) |
| { |
| if ( parent instanceof BrowserEntryPage ) |
| { |
| BrowserEntryPage entryPage = ( BrowserEntryPage ) parent; |
| Object[] objects = entryPage.getChildren(); |
| if ( objects == null ) |
| { |
| return new String[] |
| { Messages.getString( "BrowserContentProvider.FetchingEntries" ) }; //$NON-NLS-1$ |
| } |
| else if ( objects instanceof IEntry[] ) |
| { |
| IEntry[] entries = ( IEntry[] ) objects; |
| return entries; |
| } |
| else |
| { |
| return objects; |
| } |
| } |
| else if ( parent instanceof IRootDSE ) |
| { |
| final IRootDSE rootDSE = ( IRootDSE ) parent; |
| |
| if ( !rootDSE.isChildrenInitialized() ) |
| { |
| new StudioBrowserJob( new InitializeChildrenRunnable( false, rootDSE ) ).execute(); |
| return new String[] |
| { Messages.getString( "BrowserContentProvider.FetchingEntries" ) }; //$NON-NLS-1$ |
| } |
| |
| // get base entries |
| List<IEntry> entryList = new ArrayList<IEntry>(); |
| entryList.addAll( Arrays.asList( rootDSE.getChildren() ) ); |
| |
| // remove non-visible entries |
| for ( Iterator<IEntry> it = entryList.iterator(); it.hasNext(); ) |
| { |
| Object o = it.next(); |
| if ( !preferences.isShowDirectoryMetaEntries() && ( o instanceof DirectoryMetadataEntry ) ) |
| { |
| it.remove(); |
| } |
| } |
| |
| return entryList.toArray(); |
| } |
| else if ( parent instanceof IEntry ) |
| { |
| final IEntry parentEntry = ( IEntry ) parent; |
| IQuickSearch quickSearch = parentEntry.getBrowserConnection().getQuickSearch(); |
| |
| if ( parentEntry instanceof IContinuation ) |
| { |
| IContinuation continuation = ( IContinuation ) parentEntry; |
| if ( continuation.getState() == State.UNRESOLVED ) |
| { |
| continuation.resolve(); |
| } |
| if ( continuation.getState() == State.CANCELED ) |
| { |
| return new Object[0]; |
| } |
| } |
| |
| if ( !parentEntry.isChildrenInitialized() ) |
| { |
| new StudioBrowserJob( new InitializeChildrenRunnable( false, parentEntry ) ).execute(); |
| return new String[] |
| { Messages.getString( "BrowserContentProvider.FetchingEntries" ) }; //$NON-NLS-1$ |
| } |
| else if ( parentEntry.getChildrenCount() <= preferences.getFoldingSize() || !preferences.isUseFolding() ) |
| { |
| if ( entryToEntryPagesMap.containsKey( parentEntry ) ) |
| { |
| entryToEntryPagesMap.remove( parentEntry ); |
| } |
| |
| IEntry[] results = parentEntry.getChildren(); |
| |
| List<Object> objects = new ArrayList<Object>(); |
| |
| if ( quickSearch != null |
| && parentEntry.getDn().equals( quickSearch.getSearchBase() ) ) |
| { |
| objects.add( quickSearch ); |
| } |
| |
| if ( parentEntry.getTopPageChildrenRunnable() != null ) |
| { |
| objects.add( parentEntry.getTopPageChildrenRunnable() ); |
| } |
| |
| objects.addAll( Arrays.asList( results ) ); |
| |
| if ( parentEntry.getNextPageChildrenRunnable() != null ) |
| { |
| objects.add( parentEntry.getNextPageChildrenRunnable() ); |
| } |
| |
| return objects.toArray(); |
| } |
| else |
| { |
| BrowserEntryPage[] entryPages = getEntryPages( parentEntry ); |
| |
| List<Object> objects = new ArrayList<Object>(); |
| |
| if ( quickSearch != null |
| && parentEntry.getDn().equals( quickSearch.getSearchBase() ) ) |
| { |
| objects.add( quickSearch ); |
| } |
| |
| objects.addAll( Arrays.asList( entryPages ) ); |
| |
| return objects.toArray(); |
| } |
| } |
| else if ( parent instanceof BrowserSearchResultPage ) |
| { |
| BrowserSearchResultPage srPage = ( BrowserSearchResultPage ) parent; |
| Object[] objects = srPage.getChildren(); |
| if ( objects == null ) |
| { |
| return new String[] |
| { Messages.getString( "BrowserContentProvider.FetchingSearchResults" ) }; //$NON-NLS-1$ |
| } |
| else if ( objects instanceof ISearchResult[] ) |
| { |
| ISearchResult[] srs = ( ISearchResult[] ) objects; |
| return srs; |
| } |
| else |
| { |
| return objects; |
| } |
| } |
| else if ( parent instanceof ISearch ) |
| { |
| ISearch search = ( ISearch ) parent; |
| if ( search instanceof IContinuation ) |
| { |
| IContinuation continuation = ( IContinuation ) search; |
| if ( continuation.getState() == State.UNRESOLVED ) |
| { |
| continuation.resolve(); |
| } |
| if ( continuation.getState() == State.CANCELED ) |
| { |
| return new Object[0]; |
| } |
| } |
| |
| if ( search.getSearchResults() == null || search.getSearchContinuations() == null ) |
| { |
| new StudioBrowserJob( new SearchRunnable( new ISearch[] |
| { search } ) ).execute(); |
| return new String[] |
| { Messages.getString( "BrowserContentProvider.PerformingSearch" ) }; //$NON-NLS-1$ |
| } |
| else if ( search.getSearchResults().length + search.getSearchContinuations().length == 0 ) |
| { |
| return new String[] |
| { Messages.getString( "BrowserContentProvider.NoResults" ) }; //$NON-NLS-1$ |
| } |
| else if ( search.getSearchResults().length <= preferences.getFoldingSize() || !preferences.isUseFolding() ) |
| { |
| if ( searchToSearchResultPagesMap.containsKey( search ) ) |
| { |
| searchToSearchResultPagesMap.remove( search ); |
| } |
| |
| ISearchResult[] results = search.getSearchResults(); |
| SearchContinuation[] scs = search.getSearchContinuations(); |
| List<Object> objects = new ArrayList<Object>(); |
| |
| if ( search.getTopSearchRunnable() != null ) |
| { |
| objects.add( search.getTopSearchRunnable() ); |
| } |
| |
| objects.addAll( Arrays.asList( results ) ); |
| |
| if ( scs != null ) |
| { |
| objects.addAll( Arrays.asList( scs ) ); |
| } |
| |
| if ( search.getNextSearchRunnable() != null ) |
| { |
| objects.add( search.getNextSearchRunnable() ); |
| } |
| |
| return objects.toArray(); |
| } |
| else |
| { |
| BrowserSearchResultPage[] srPages = getSearchResultPages( search ); |
| return srPages; |
| } |
| } |
| else if ( parent instanceof BrowserCategory ) |
| { |
| BrowserCategory category = ( BrowserCategory ) parent; |
| IBrowserConnection browserConnection = category.getParent(); |
| |
| switch ( category.getType() ) |
| { |
| case BrowserCategory.TYPE_DIT: |
| { |
| // open connection when expanding DIT |
| if ( browserConnection.getConnection() != null |
| && !browserConnection.getConnection().getConnectionWrapper().isConnected() ) |
| { |
| new StudioBrowserJob( new OpenConnectionsRunnable( browserConnection.getConnection() ) ) |
| .execute(); |
| return new String[] |
| { Messages.getString( "BrowserContentProvider.OpeningConnection" ) }; //$NON-NLS-1$ |
| } |
| |
| return new Object[] |
| { browserConnection.getRootDSE() }; |
| } |
| |
| case BrowserCategory.TYPE_SEARCHES: |
| { |
| return browserConnection.getSearchManager().getSearches().toArray(); |
| } |
| |
| case BrowserCategory.TYPE_BOOKMARKS: |
| { |
| return browserConnection.getBookmarkManager().getBookmarks(); |
| } |
| } |
| |
| return new Object[0]; |
| } |
| else |
| { |
| return new Object[0]; |
| } |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean hasChildren( Object parent ) |
| { |
| if ( parent instanceof IEntry ) |
| { |
| IEntry parentEntry = ( IEntry ) parent; |
| return parentEntry.hasChildren(); |
| } |
| else if ( parent instanceof SearchContinuation ) |
| { |
| return true; |
| } |
| else if ( parent instanceof BrowserEntryPage ) |
| { |
| return true; |
| } |
| else if ( parent instanceof BrowserSearchResultPage ) |
| { |
| return true; |
| } |
| else if ( parent instanceof ISearchResult ) |
| { |
| return false; |
| } |
| else if ( parent instanceof ISearch ) |
| { |
| return true; |
| } |
| else if ( parent instanceof BrowserCategory ) |
| { |
| return true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| |
| private BrowserEntryPage[] getEntryPages( final IEntry parentEntry ) |
| { |
| BrowserEntryPage[] entryPages; |
| if ( !entryToEntryPagesMap.containsKey( parentEntry ) ) |
| { |
| entryPages = getEntryPages( parentEntry, 0, parentEntry.getChildrenCount() - 1 ); |
| entryToEntryPagesMap.put( parentEntry, entryPages ); |
| } |
| else |
| { |
| entryPages = entryToEntryPagesMap.get( parentEntry ); |
| if ( parentEntry.getChildrenCount() - 1 != entryPages[entryPages.length - 1].getLast() ) |
| { |
| entryPages = getEntryPages( parentEntry, 0, parentEntry.getChildrenCount() - 1 ); |
| entryToEntryPagesMap.put( parentEntry, entryPages ); |
| } |
| } |
| return entryPages; |
| } |
| |
| |
| /** |
| * Creates and returns the entry pages for the given entry. The number of pages |
| * depends on the number of entries and the paging size. |
| * |
| * @param entry the parent entry |
| * @param first the index of the first child entry |
| * @param last the index of the last child entry |
| * @return the created entry pages |
| */ |
| private BrowserEntryPage[] getEntryPages( IEntry entry, int first, int last ) |
| { |
| int pagingSize = preferences.getFoldingSize(); |
| |
| int diff = last - first; |
| int factor = diff > 0 ? ( int ) ( Math.log( diff ) / Math.log( pagingSize ) ) : 0; |
| |
| int groupFirst = first; |
| int groupLast = first; |
| BrowserEntryPage[] pages = new BrowserEntryPage[( int ) ( diff / Math.pow( pagingSize, factor ) ) + 1]; |
| for ( int i = 0; i < pages.length; i++ ) |
| { |
| groupFirst = ( int ) ( i * Math.pow( pagingSize, factor ) ) + first; |
| groupLast = ( int ) ( ( i + 1 ) * Math.pow( pagingSize, factor ) ) + first - 1; |
| groupLast = groupLast > last ? last : groupLast; |
| BrowserEntryPage[] subpages = ( factor > 1 ) ? getEntryPages( entry, groupFirst, groupLast ) : null; |
| pages[i] = new BrowserEntryPage( entry, groupFirst, groupLast, subpages, sorter ); |
| } |
| |
| return pages; |
| } |
| |
| |
| private BrowserSearchResultPage[] getSearchResultPages( ISearch search ) |
| { |
| BrowserSearchResultPage[] srPages; |
| if ( !searchToSearchResultPagesMap.containsKey( search ) ) |
| { |
| srPages = getSearchResultPages( search, 0, search.getSearchResults().length - 1 ); |
| searchToSearchResultPagesMap.put( search, srPages ); |
| } |
| else |
| { |
| srPages = searchToSearchResultPagesMap.get( search ); |
| if ( search.getSearchResults().length - 1 != srPages[srPages.length - 1].getLast() ) |
| { |
| srPages = getSearchResultPages( search, 0, search.getSearchResults().length - 1 ); |
| searchToSearchResultPagesMap.put( search, srPages ); |
| } |
| } |
| return srPages; |
| } |
| |
| |
| /** |
| * Creates and returns the search result pages for the given search. The number of pages |
| * depends on the number of search results and the paging size. |
| * |
| * @param search the parent search |
| * @param first the index of the first search result |
| * @param last the index of the last child search result |
| * @return the created search result pages |
| */ |
| private BrowserSearchResultPage[] getSearchResultPages( ISearch search, int first, int last ) |
| { |
| int pagingSize = preferences.getFoldingSize(); |
| |
| int diff = last - first; |
| int factor = diff > 0 ? ( int ) ( Math.log( diff ) / Math.log( pagingSize ) ) : 0; |
| |
| int groupFirst = first; |
| int groupLast = first; |
| BrowserSearchResultPage[] pages = new BrowserSearchResultPage[( int ) ( diff / Math.pow( pagingSize, factor ) ) + 1]; |
| for ( int i = 0; i < pages.length; i++ ) |
| { |
| groupFirst = ( int ) ( i * Math.pow( pagingSize, factor ) ) + first; |
| groupLast = ( int ) ( ( i + 1 ) * Math.pow( pagingSize, factor ) ) + first - 1; |
| groupLast = groupLast > last ? last : groupLast; |
| BrowserSearchResultPage[] subpages = ( factor > 1 ) ? getSearchResultPages( search, groupFirst, groupLast ) |
| : null; |
| pages[i] = new BrowserSearchResultPage( search, groupFirst, groupLast, subpages, sorter ); |
| } |
| |
| return pages; |
| } |
| } |