package org.basex.gui.view.map;
import org.basex.data.Data;
import org.basex.gui.GUIProp;
import org.basex.gui.view.ViewData;
/**
* Defines shared things of TreeMap layout algorithms.
*
* @author BaseX Team 2005-12, BSD License
* @author Joerg Hauser
*/
final class MapLayout {
/** List of rectangles. */
final MapRects rectangles = new MapRects();
/** Font size. */
private final int off;
/** Data reference. */
private final Data data;
/** Map algorithm to use in this layout. */
private final MapAlgo algo;
/** Text lengths. */
private final int[] textLen;
/** Widow properties. */
private final GUIProp prop;
/** Layout rectangle. */
final MapRect layout;
/**
* Constructor.
* @param d data reference to use in this layout
* @param tl text lengths array
* @param pr gui properties
*/
MapLayout(final Data d, final int[] tl, final GUIProp pr) {
data = d;
textLen = tl;
prop = pr;
off = prop.num(GUIProp.FONTSIZE) + 4;
switch(prop.num(GUIProp.MAPOFFSETS)) {
// no title, small border
case 1 :
layout = new MapRect(0, 2, 0, 2); break;
// title, no border
case 2 :
layout = new MapRect(0, off, 0, off); break;
// title, border
case 3 :
layout = new MapRect(2, off - 1, 4, off + 1); break;
// title, large border
case 4 :
layout = new MapRect(off >> 2, off, off >> 1, off + (off >> 2)); break;
// no title, no border
default:
layout = new MapRect(0, 0, 0, 0); break;
}
switch(prop.num(GUIProp.MAPALGO)) {
// select method to construct this treemap
// may should be placed in makeMap to define different method for
// different levels
case 1 : algo = new StripAlgo(); break;
case 2 : algo = new SquarifiedAlgo(); break;
case 3 : algo = new SliceDiceAlgo(); break;
case 4 : algo = new BinaryAlgo(); break;
default: algo = new SplitAlgo(); break;
}
}
/**
* Returns all children of the specified node.
* @param par parent node
* @return children
*/
private MapList children(final int par) {
final MapList list = new MapList();
final int last = par + ViewData.size(data, par);
final boolean atts = prop.is(GUIProp.MAPATTS);
int p = par + (atts ? 1 : data.attSize(par, data.kind(par)));
while(p < last) {
list.add(p);
p += ViewData.size(data, p);
}
return list;
}
/**
* Recursively splits rectangles.
* @param r parent rectangle
* @param l children array
* @param ns start array position
* @param ne end array position
*/
void makeMap(final MapRect r, final MapList l, final int ns, final int ne) {
if(ne - ns == 0) {
// one rectangle left, add it and go deeper
r.pre = l.get(ns);
putRect(r);
} else {
int nn = 0;
if(r.level == 0) {
final int is = l.size();
for(int i = 0; i < is; ++i) nn += ViewData.size(data, l.get(i));
} else {
nn = l.get(ne) - l.get(ns) + ViewData.size(data, l.get(ne));
}
l.initWeights(textLen, nn, data, prop.num(GUIProp.MAPWEIGHT));
// call recursion for next deeper levels
final MapRects rects = algo.calcMap(r, l, ns, ne);
for(final MapRect rect : rects) {
if(rect.x + rect.w <= r.x + r.w && rect.y + rect.h <= r.y + r.h)
putRect(rect);
}
}
}
/**
* One rectangle left, add it and continue with its children.
* @param r parent rectangle
*/
private void putRect(final MapRect r) {
// position, with and height calculated using sizes of former level
final int x = r.x + layout.x;
final int y = r.y + layout.y;
final int w = r.w - layout.w;
final int h = r.h - layout.h;
// skip too small rectangles and meta data in file systems
if(w < off && h < off || w <= 2 || h <= 2) {
rectangles.add(r);
return;
}
rectangles.add(r);
final MapList ch = children(r.pre);
final int cs = ch.size();
if(cs != 0) {
makeMap(new MapRect(x, y, w, h, r.pre, r.level + 1), ch, 0, cs - 1);
}
}
}