/**
* This file is part of Archiv-Editor.
*
* The software Archiv-Editor serves as a client user interface for working with
* the Person Data Repository. See: pdr.bbaw.de
*
* The software Archiv-Editor was developed at the Berlin-Brandenburg Academy
* of Sciences and Humanities, Jägerstr. 22/23, D-10117 Berlin.
* www.bbaw.de
*
* Copyright (C) 2010-2013 Berlin-Brandenburg Academy
* of Sciences and Humanities
*
* The software Archiv-Editor was developed by @author: Christoph Plutte.
*
* Archiv-Editor is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Archiv-Editor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Archiv-Editor.
* If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*/
package org.bbaw.pdr.ae.view.control.provider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;
import org.bbaw.pdr.ae.common.AEConstants;
import org.bbaw.pdr.ae.common.CommonActivator;
import org.bbaw.pdr.ae.common.NLMessages;
import org.bbaw.pdr.ae.control.facade.Facade;
import org.bbaw.pdr.ae.metamodel.PdrId;
import org.bbaw.pdr.ae.model.Aspect;
import org.bbaw.pdr.ae.model.Concurrence;
import org.bbaw.pdr.ae.model.PdrObject;
import org.bbaw.pdr.ae.model.Person;
import org.bbaw.pdr.ae.model.ReferenceMods;
import org.bbaw.pdr.ae.model.view.FacetResultNode;
import org.bbaw.pdr.ae.model.view.TreeNode;
import org.bbaw.pdr.ae.view.control.comparator.PdrObjectsByDisplayNameComparator;
import org.bbaw.pdr.ae.view.control.internal.Activator;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
/**
* @author cplutte Class provides the Content for the TreeViewer. TODO has to be
* adapted to dynamic Data.
*/
public class TreeContentProvider implements ITreeContentProvider
{
/** Logger. */
private static ILog iLogger = AEConstants.ILOGGER;
/** status. */
private IStatus _log;
/** _facade singleton instance. */
private Facade _facade = Facade.getInstanz();
/** The _type. */
private String _type;
/** The _index. */
private int _index;
/** The _objects. */
private Vector<PdrObject> _objects;
/** The _ref by host only. */
private boolean _refByHostOnly = false;
/** The _is reference. */
private boolean _isReference = false;
/** The _max_depth. */
private int _maxdepth = 3;
/** The _ ma x_ leaves. */
private static final int MAXLEAVES = 30;
/** The _ fir s_ character. */
private static final String FIRSCHARACTER = AEConstants.ALPHABET_EXTENDED[0];
/** The _ las t_ character. */
private static final String LAST_CHARACTER = AEConstants.ALPHABET_EXTENDED[AEConstants.ALPHABET_EXTENDED.length - 1];
/**
* Adds the hosted references.
* @param host the host
* @param hostTN the host tn
* @param recursionLevel the recursion level
*/
private void addHostedReferences(final ReferenceMods host, final TreeNode hostTN, final int recursionLevel)
{
if (host.getHostedReferences() != null)
{
for (String id : host.getHostedReferences())
{
ReferenceMods hosted = _facade.getReference(new PdrId(id));
TreeNode hostedTN = null;
if (hosted != null)
{
hostedTN = new TreeNode(hosted.getDisplayName(), hosted);
hostTN.addChild(hostedTN);
if (recursionLevel <= 2 && hosted.getHostedReferences() != null
&& hosted.getHostedReferences().size() > 0)
{
addHostedReferences(hosted, hostedTN, recursionLevel + 1);
}
}
try
{
checkUpdateState(hosted, hostedTN);
processUpdateState(hostTN, hostedTN);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
/**
* Check update state.
* @param o the o
* @param objTn the obj tn
* @throws Exception the exception
*/
private void checkUpdateState(final PdrObject o, final TreeNode objTn) throws Exception
{
if (o instanceof Person)
{
if (_facade.getPersonsUpdateState().containsKey(o.getPdrId().toString()))
{
if (_facade.getPersonsUpdateState().get(o.getPdrId().toString()) == 1)
{
objTn.setUpdated(true);
}
else if (o.getPdrId().getId() > 99999999)
{
objTn.setNew(true);
}
}
}
if (o instanceof Aspect)
{
if (_facade.getAspectsUpdateState().containsKey(o.getPdrId().toString()))
{
if (_facade.getAspectsUpdateState().get(o.getPdrId().toString()) == 1)
{
objTn.setUpdated(true);
}
else if (o.getPdrId().getId() > 99999999)
{
objTn.setNew(true);
}
}
}
if (o instanceof ReferenceMods)
{
if (_facade.getReferencesUpdateState().containsKey(o.getPdrId().toString()))
{
if (_facade.getReferencesUpdateState().get(o.getPdrId().toString()) == 1)
{
objTn.setUpdated(true);
}
else if (o.getPdrId().getId() > 99999999)
{
objTn.setNew(true);
}
}
}
}
/**
* Creates the object node.
* @param o the o
* @param tn the tn
* @param sameNameTN the same name tn
* @return the tree node
*/
private TreeNode createObjectNode(final PdrObject o, final TreeNode tn, final boolean sameNameTN)
{
// create new treenode and add object.
TreeNode objTn;
objTn = new TreeNode(o.getDisplayName(), o);
if (_isReference && o instanceof ReferenceMods)
{
ReferenceMods r = (ReferenceMods) o;
if (!_refByHostOnly || !r.isHosted())
{
tn.addChild(objTn);
}
if (r.getHostedReferences() != null && !r.getHostedReferences().isEmpty())
{
addHostedReferences(r, objTn, 0);
}
}
else
{
tn.addChild(objTn);
}
try
{
checkUpdateState(o, objTn);
}
catch (Exception e)
{
e.printStackTrace();
}
processUpdateState(objTn, tn);
// if treeNode is node which has an object of the same name.
if (sameNameTN)
{
if (tn.getPdrObject() != null)
{
TreeNode tn2 = new TreeNode(tn.getPdrObject().getDisplayName(), tn.getPdrObject());
processUpdateState(tn, tn2);
tn.addChild(tn2);
tn.setPdrObject(null);
}
tn.setNumberOfLeaves(tn.getChildren().length);
return tn;
}
return objTn;
}
/**
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
@Override
public void dispose()
{
// TODO Auto-generated method stub
}
@Override
public final Object[] getChildren(final Object parentElement)
{
return ((TreeNode) parentElement).getChildren();
}
@SuppressWarnings("unchecked")
@Override
public final Object[] getElements(final Object inputElement)
{
// System.out.println("getElements " + _index);
_refByHostOnly = Platform.getPreferencesService().getBoolean(CommonActivator.PLUGIN_ID,
"REFERENCE_TREE_ONLY_BYHOST", false, null); // Activator.getDefault().getPreferenceStore().getBoolean("REFERENCE_TREE_ONLY_BYHOST");
TreeNode root = null;
if (inputElement instanceof Vector<?>)
{
if (((Vector<?>) inputElement) != null && !((Vector<?>) inputElement).isEmpty()
&& ((Vector<?>) inputElement).firstElement() != null
&& ((Vector<?>) inputElement).firstElement() instanceof PdrObject)
{
_objects = (Vector<PdrObject>) inputElement;
Collections.sort(_objects, new PdrObjectsByDisplayNameComparator());
_isReference = false;
if (((Vector<?>) inputElement).firstElement() instanceof Aspect)
{
_type = "pdrAo";
System.out.println("TreeContentProvider type: pdrAo");
}
else if (((Vector<?>) inputElement).firstElement() instanceof Person)
{
_type = "pdrPo";
}
else if (((Vector<?>) inputElement).firstElement() instanceof ReferenceMods)
{
_type = "pdrRo";
_isReference = true;
}
else
{
_type = "error";
}
root = new TreeNode("root", _type); //$NON-NLS-1$ //$NON-NLS-2$
root = transformToNode(root, _objects, _type, 1);
}
else if (((Vector<?>) inputElement) != null && !((Vector<?>) inputElement).isEmpty()
&& ((Vector<?>) inputElement).firstElement() instanceof FacetResultNode)
{
Vector<FacetResultNode> facetNodes = (Vector<FacetResultNode>) inputElement;
root = new TreeNode("root", "facet"); //$NON-NLS-1$ //$NON-NLS-2$
for (FacetResultNode facetNode : facetNodes)
{
// _log = new Status(IStatus.INFO, Activator.PLUGIN_ID,
// "TreeContentProvider facet " + facetNode.getId()); //$NON-NLS-1$
// iLogger.log(_log);
if (facetNode.getObjects() != null && !facetNode.getObjects().isEmpty())
{
_objects = facetNode.getObjects();
Collections.sort(_objects, new PdrObjectsByDisplayNameComparator());
_isReference = false;
if (((Vector<?>) _objects).firstElement() instanceof Aspect)
{
_type = "pdrAo";
System.out.println("TreeContentProvider type: pdrAo");
}
else if (((Vector<?>) _objects).firstElement() instanceof Person)
{
_type = "pdrPo";
}
else if (((Vector<?>) _objects).firstElement() instanceof ReferenceMods)
{
_type = "pdrRo";
_isReference = true;
}
else
{
_type = "error";
}
facetNode = (FacetResultNode) transformToNode(facetNode, _objects, _type, 1);
if (facetNode.getNumberOfLeaves() > 0)
{
root.addChild(facetNode);
}
}
else
{
root.addChild(facetNode);
}
}
}
else
{
root = new TreeNode("root", "noResult"); //$NON-NLS-1$ //$NON-NLS-2$
TreeNode tnId = new TreeNode(NLMessages.getString("ViewProvider_no_result"), "noResult"); //$NON-NLS-2$
root.addChild(tnId);
_log = new Status(IStatus.INFO, Activator.PLUGIN_ID, "TreeContentProvider no result for tree"); //$NON-NLS-1$
iLogger.log(_log);
}
_log = new Status(IStatus.INFO, Activator.PLUGIN_ID, "TreeContentProvider transformed to nodes"); //$NON-NLS-1$
iLogger.log(_log);
}
else if (inputElement instanceof HashMap<?, ?>)
{
if (((HashMap<?, ?>) inputElement) != null && !((HashMap<?, ?>) inputElement).isEmpty())
{
_log = new Status(IStatus.INFO, Activator.PLUGIN_ID, "TreeContentProvider input hashmap"); //$NON-NLS-1$
iLogger.log(_log);
HashMap<PdrId, PdrObject> map = (HashMap<PdrId, PdrObject>) inputElement;
for (PdrId key : map.keySet())
{
if (map.get(key) instanceof PdrObject)
{
if (map.get(key) instanceof Aspect)
{
_type = "pdrAo";
System.out.println("TreeContentProvider type: pdrAo");
}
else if (map.get(key) instanceof Person)
{
_type = "pdrPo";
}
else if (map.get(key) instanceof ReferenceMods)
{
_type = "pdrRo";
_isReference = true;
}
else
{
_type = "error";
}
_objects = new Vector<PdrObject>(map.size());
for (PdrId k : map.keySet())
{
_objects.add(map.get(k));
}
Collections.sort(_objects, new PdrObjectsByDisplayNameComparator());
root = new TreeNode("root", _type); //$NON-NLS-1$ //$NON-NLS-2$
root = transformToNode(root, _objects, _type, 1);
break;
}
}
}
}
else if (inputElement instanceof TreeNode)
{
return ((TreeNode) inputElement).getChildren();
}
else
{
root = new TreeNode("root", "noResult"); //$NON-NLS-1$ //$NON-NLS-2$
TreeNode tnId = new TreeNode(NLMessages.getString("ViewProvider_no_result"), "noResult"); //$NON-NLS-2$
root.addChild(tnId);
_log = new Status(IStatus.INFO, Activator.PLUGIN_ID, "TreeContentProvider No Result"); //$NON-NLS-1$
iLogger.log(_log);
}
if (root == null || root.getChildren() == null)
{
root = new TreeNode("root", "noResult"); //$NON-NLS-1$ //$NON-NLS-2$
TreeNode tnId = new TreeNode(NLMessages.getString("ViewProvider_not_result"), "noResult"); //$NON-NLS-2$
root.addChild(tnId);
_log = new Status(IStatus.INFO, Activator.PLUGIN_ID, "TreeContentProvider No Result"); //$NON-NLS-1$
iLogger.log(_log);
}
return root.getChildren();
}
@Override
public final Object getParent(final Object element)
{
return ((TreeNode) element).getParent();
}
@Override
public final boolean hasChildren(final Object element)
{
TreeNode tn = (TreeNode) element;
if (tn.hasChildren())
{
return true;
}
else if (tn.getPdrQuery() != null)
{
return true;
}
else
{
return false;
}
}
@Override
public void inputChanged(final Viewer arg0, final Object arg1, final Object arg2)
{
// TODO Auto-generated method stub
}
/**
* Optimize.
* @param tn the tn
*/
private void optimize(final TreeNode tn)
{
if (tn.getNumberOfLeaves() == 0)
{
tn.setChildren(null);
}
else if (tn.getNumberOfLeaves() < MAXLEAVES)
{
if (tn.hasChildren() && tn.getChildren() != null)
{
List<TreeNode> leeves = new ArrayList<TreeNode>(tn.getNumberOfLeaves());
for (TreeNode child : tn.getChildren())
{
if (child.getChildren() != null)
{
for (TreeNode leef : child.getChildren())
{
leeves.add(leef);
}
}
}
tn.setChildren(leeves);
}
}
}
/**
* Process end.
* @param str the str
* @return the string
*/
private String processEnd(String str)
{
String c;
if (str.length() < _maxdepth - 1)
{
while (str.length() <= _maxdepth)
{
str = str + FIRSCHARACTER;
}
return str;
}
else if (str.endsWith(LAST_CHARACTER))
{
while (str.length() > 0 && str.endsWith(LAST_CHARACTER))
{
str = str.substring(0, str.length() - 1);
}
if (str.length() > 0)
{
c = str.substring(str.length() - 1, str.length());
for (int i = 0; i < AEConstants.ALPHABET_EXTENDED.length - 1; i++)
{
if (AEConstants.ALPHABET_EXTENDED[i].equalsIgnoreCase(c))
{
c = AEConstants.ALPHABET_EXTENDED[i + 1];
break;
}
}
str = str.substring(0, str.length() - 1) + c;
}
else
{
return null;
}
}
else
{
if (str.length() > 0)
{
c = str.substring(str.length() - 1, str.length());
for (int i = 0; i < AEConstants.ALPHABET_EXTENDED.length - 1; i++)
{
if (AEConstants.ALPHABET_EXTENDED[i].equalsIgnoreCase(c))
{
c = AEConstants.ALPHABET_EXTENDED[i + 1];
break;
}
}
str = str + c;
}
}
return str;
}
/**
* Process leaves.
* @param tn the tn
* @param begin the begin
* @param position the position
* @param objects the objects
* @param type the type
* @return the tree node
*/
public final TreeNode processLeaves(final TreeNode tn, final String begin, final int position,
final Vector<PdrObject> objects, final String type)
{
int count = 0;
PdrObject o;
TreeNode lastNode = null;
String lastName = null;
if (begin.equals("?"))
{
while (_index < objects.size() && objects.get(_index).getDisplayName().compareToIgnoreCase("a") < 0) //$NON-NLS-1$
{
o = objects.get(_index);
if (o.getDisplayName().equals(lastName))
{
lastNode = createObjectNode(o, lastNode, true);
}
else
{
lastNode = createObjectNode(o, tn, false);
}
if (type.equals("pdrPo") && o instanceof Person)
{
processConcurrences(o, lastNode);
}
lastName = o.getDisplayName();
count++;
_index++;
}
}
else if (begin.endsWith(LAST_CHARACTER))
{
String end = processEnd(begin);
if (end != null)
{
while (_index < objects.size() && objects.get(_index).getDisplayName().compareToIgnoreCase(end) < 0) //$NON-NLS-1$
{
o = objects.get(_index);
if (o.getDisplayName().equals(lastName))
{
lastNode = createObjectNode(o, lastNode, true);
}
else
{
lastNode = createObjectNode(o, tn, false);
}
if (type.equals("pdrPo") && o instanceof Person)
{
processConcurrences(o, lastNode);
}
lastName = o.getDisplayName();
count++;
_index++;
}
}
else
{
while (_index < objects.size()
&& objects.get(_index).getDisplayName().compareToIgnoreCase(LAST_CHARACTER) > 0) //$NON-NLS-1$
{
o = objects.get(_index);
if (o.getDisplayName().equals(lastName))
{
lastNode = createObjectNode(o, lastNode, true);
}
else
{
lastNode = createObjectNode(o, tn, false);
}
if (type.equals("pdrPo") && o instanceof Person)
{
processConcurrences(o, lastNode);
}
lastName = o.getDisplayName();
count++;
_index++;
}
}
}
else
{
while (_index < objects.size() && objects.get(_index).getDisplayName().toLowerCase().startsWith(begin)) //$NON-NLS-1$
{
o = objects.get(_index);
if (o.getDisplayName().equals(lastName))
{
lastNode = createObjectNode(o, lastNode, true);
}
else
{
lastNode = createObjectNode(o, tn, false);
}
if (type.equals("pdrPo") && o instanceof Person)
{
processConcurrences(o, lastNode);
}
lastName = o.getDisplayName();
count++;
_index++;
}
}
tn.setNumberOfLeaves(count);
return tn;
}
private void processConcurrences(PdrObject o, TreeNode lastNode)
{
Person mainPerson = (Person) o;
if (mainPerson.getConcurrences() != null && mainPerson.getConcurrences().getConcurrences() != null)
{
for (Concurrence c : mainPerson.getConcurrences().getConcurrences())
{
if (c.getPersonId() != null)
{
Person concurringPerson = _facade.getPerson(c.getPersonId());
if (concurringPerson != null)
{
createObjectNode(concurringPerson, lastNode, false);
}
}
}
lastNode.setNumberOfLeaves(lastNode.getChildren().length);
}
}
/**
* Process nodes.
* @param tn the tn
* @param objects the objects
* @param begin the begin
* @param position the position
* @param type the type
* @return the tree node
*/
private TreeNode processNodes(final TreeNode tn, final Vector<PdrObject> objects, final String begin,
final int position, final String type)
{
TreeNode child;
String newBegin = begin;
int count = 0;
String chr = null;
for (int i = 0; i < AEConstants.ALPHABET_EXTENDED.length; i++)
{
chr = AEConstants.ALPHABET_EXTENDED[i];
newBegin = begin + chr;
child = new TreeNode(newBegin, type);
if (position < _maxdepth)
{
child = processNodes(child, objects, newBegin, position + 1, type);
}
else
{
child = processLeaves(child, newBegin, position, objects, type);
}
if (child.getNumberOfLeaves() > 0)
{
tn.addChild(child);
processUpdateState(child, tn);
}
count = count + child.getNumberOfLeaves();
}
tn.setNumberOfLeaves(count);
optimize(tn);
return tn;
}
/**
* Process update state.
* @param objTn the obj tn
* @param tn the tn
*/
private void processUpdateState(final TreeNode objTn, final TreeNode tn)
{
if (objTn.isUpdated())
{
tn.setUpdated(true);
}
if (objTn.isNew())
{
tn.setNew(true);
}
}
/**
* Transform to node.
* @param root the root
* @param objects the objects
* @param type the type
* @param position the position
* @return the tree node
*/
public TreeNode transformToNode(TreeNode root, final Vector<PdrObject> objects, final String type,
final int position)
{
_index = 0;
if (objects.size() < 30)
{
_maxdepth = 1;
}
else if (objects.size() < 500)
{
_maxdepth = 2;
}
else if (objects.size() < 10000)
{
_maxdepth = 3;
}
else
{
_maxdepth = 4;
}
String begin;
TreeNode child;
for (int j = 0; j < 10; j++)
{
begin = new Integer(j).toString();
child = new TreeNode(begin, type);
child = processLeaves(child, begin, position, objects, type);
if (child.getNumberOfLeaves() > 0)
{
root.addChild(child);
}
}
begin = "?";
child = new TreeNode(begin, type);
child = processLeaves(child, begin, position, objects, type);
if (child.getNumberOfLeaves() > 0)
{
root.addChild(child);
}
begin = "";
root = processNodes(root, objects, begin, position, type);
return root;
}
}