blob: b58e7801edb28c202cdc0ea23f56e1e1b92c6e97 [file] [log] [blame]
/*
* 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;
}
}