/* Copyright (C) 2006 Christian Schneider
*
* This file is part of Nomad.
*
* Nomad is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Nomad 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Nomad; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.sf.nmedit.jpatch;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class LayoutTool
{
private PModuleContainer container;
private List<PModule> moving ;
private int dx;
private int dy;
public LayoutTool(PModuleContainer container, int initialCapacity)
{
this.container = container;
moving = new ArrayList<PModule>(initialCapacity);
}
public LayoutTool(PModuleContainer container, Collection<PModule> moved)
{
this.container = container;
moving = new ArrayList<PModule>(moved);
}
public void setDelta(int x, int y)
{
this.dx = x;
this.dy = y;
}
public void setDelta(Point delta)
{
setDelta(delta.x, delta.y);
}
public void add(PModule module)
{
moving.add(module);
}
public Object[] move()
{
return _move();
}
// sorts by column, then by row
private final Comparator<PModule> Y_ORDER = new YOrder();
private Object[] _move()
{
if (container == null)
return new Object[0]; // implies that no modules were added to the tool
// metrics
PModuleMetrics metrics = container.getModuleMetrics();
// maps containing (column, list(module)) pairs
Map<Integer, List<PModule>> movCols = new HashMap<Integer, List<PModule>>();
Map<Integer, List<PModule>> fixCols = new HashMap<Integer, List<PModule>>();
// compute bounds, add modules to map
int minx = Integer.MAX_VALUE;
int maxx = 0;
int miny = Integer.MAX_VALUE;
int maxy = 0;
int tx = dx;
int ty = dy;
int minyunaligned = Integer.MAX_VALUE;
for (PModule m: moving)
{
int sy = m.getScreenY()+ty;
int ax = metrics.alignScreenX(m.getScreenX()+tx);
int ay = metrics.alignScreenY(sy);
minyunaligned = Math.min(minyunaligned, sy);
minx = Math.min(minx, ax);
maxx = Math.max(maxx, ax+m.getScreenWidth() -1);
miny = Math.min(miny, ay);
maxy = Math.max(maxy, ay+m.getScreenHeight()-1);
add(movCols, ax, m);
}
{
int d = minyunaligned-miny;
ty-=d;
}
if (minx <0)
{
tx -= minx;
maxx -= minx;
minx = 0;
}
if (miny < 0)
{
ty -= miny;
maxy -= miny;
miny = 0;
}
// find modules which might be moved
for (PModule m: container)
{
int sx = m.getScreenX();
int sb = m.getScreenY()+m.getScreenHeight()-1;
if (sb>=miny && movCols.containsKey(sx) && (!moving.contains(m)))
add(fixCols, sx, m);
}
// see if modules have to be moved down more than dy
{
int add_y = 0;
for (List<PModule> list: fixCols.values())
for (PModule m: list)
{
int m_h = m.getScreenHeight();
int m_y = m.getScreenY();
int m_bot = m_y+m_h-1;
if (m_y<miny && miny<=m_bot)
{
add_y = Math.max(add_y, m_bot-miny+1);
}
}
miny+=add_y;
maxy+=add_y;
ty+=add_y;
}
List<Object> layout = new ArrayList<Object>(moving.size());
// moved modules
for (Integer sx: movCols.keySet())
{
int top = miny;
// move column
for (PModule m: movCols.get(sx))
{
int sy = metrics.alignScreenY(ty+m.getScreenY());
layout.add(m);
layout.add(sx);
layout.add(sy);
top = Math.max(top, sy+m.getScreenHeight());
}
// indirect movements
List<PModule> indirect = fixCols.get(sx);
if (indirect != null)
{
Collections.sort(indirect, Y_ORDER);
for (PModule m: indirect)
{
int sy = m.getScreenY();
int sb = sy+m.getScreenHeight()-1;
if (sb<miny) continue;
int add_y = top-sy;
if (add_y<=0) break;
int ny = sy+add_y; // new y location
layout.add(m);
layout.add(sx);
layout.add(ny);
top = ny+m.getScreenHeight();
}
}
}
return layout.toArray();
}
private void add(Map<Integer, List<PModule>> map, int key, PModule m)
{
List<PModule> list = map.get(key);
if (list == null)
map.put(key, list = new ArrayList<PModule>(1));
list.add(m);
}
private static class YOrder implements Comparator<PModule>
{
public int compare(PModule a, PModule b)
{
return Integer.signum(a.getScreenY()-b.getScreenY());
}
}
}