// This file is part of AceWiki. // Copyright 2008-2013, AceWiki developers. // // AceWiki 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. // // AceWiki 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 AceWiki. If // not, see http://www.gnu.org/licenses/. package ch.uzh.ifi.attempto.preditor; import java.util.ArrayList; import java.util.List; import nextapp.echo.app.Column; import nextapp.echo.app.Extent; /** * This class represents a column of menu blocks. * * @author Tobias Kuhn */ class MenuBlockColumn { private PreditorWindow preditor; private List<MenuBlockContent> contents = new ArrayList<MenuBlockContent>(); private int heightUnits, weight; /** * Creates a new menu block column. * * @param preditor The predictive editor object. */ private MenuBlockColumn(PreditorWindow preditor) { this.preditor = preditor; } /** * Creates a new menu block column with one menu block. * * @param content The content of the menu block. * @param preditor The predictive editor object. */ public MenuBlockColumn(MenuBlockContent content, PreditorWindow preditor) { this.preditor = preditor; contents.add(content); updateValues(); } /** * Includes the menu blocks of the other column at the bottom of this one. * * @param other The other menu block column. */ public void includeAtBottom(MenuBlockColumn other) { this.contents.addAll(other.contents); updateValues(); } /** * Includes the menu blocks of the other column at the top of this one. * * @param other The other menu block column. */ public void includeAtTop(MenuBlockColumn other) { this.contents.addAll(0, other.contents); updateValues(); } /** * Returns two menu block columns which contain the splitted content of this one. This object * remains unchanged. The trend value indicates how to split odd numbers of menu blocks. * * @param trend If positive, odd numbers are split in a way that the first column has more menu * block, and vice versa for negative values. * @return Two menu blocks in an array. */ public MenuBlockColumn[] getSplitted(int trend) { MenuBlockColumn c1 = new MenuBlockColumn(preditor); MenuBlockColumn c2 = new MenuBlockColumn(preditor); int threshold; if (trend > 0) { threshold = (int) ((contents.size() + 0.5) / 2); } else { threshold = contents.size() / 2; } for (int i=0 ; i < contents.size() ; i++) { if (i < threshold) { c1.contents.add(contents.get(i)); } else { c2.contents.add(contents.get(i)); } } c1.updateValues(); c2.updateValues(); return new MenuBlockColumn[] {c1, c2}; } private void updateValues() { int hu = 2 * contents.size(); for (MenuBlockContent c : contents) { int u = c.getUnfilteredItemCount(); if (u < 32) { hu += u; } else { hu += 32; } } heightUnits = hu; weight = heightUnits * contents.size(); } /** * Returns the number of height units necessary to optimally display this menu block column. * Menu blocks with a height of more than 32 units only count as 32 units. * * @return The number of height units. */ public int getHeightUnits() { return heightUnits; } /** * This method returns the "weight" of this column. This value should quantify the complexity * of this column. * * @return The weight of this column. */ public int getWeight() { return weight; } /** * Creates and returns the GUI component of this menu block column. * * @param width The width of the column. * @return The GUI component. */ public Column createGUI(int width) { Column column = new Column(); column.setCellSpacing(new Extent(10)); int totalUnits = 18; int unitsRest = totalUnits - (2 * contents.size()); int freeUnits = unitsRest; int freeBlocksCount = contents.size(); double avHeightUnits = (double) unitsRest / contents.size(); boolean overfull = totalUnits - heightUnits < 0; boolean even = true; for (MenuBlockContent c : contents) { if (overfull && c.getUnfilteredItemCount() <= avHeightUnits) { even = false; break; } else if (!overfull && c.getUnfilteredItemCount() >= avHeightUnits) { even = false; break; } } if (!even && overfull) { List<MenuBlockContent> largeContents = new ArrayList<MenuBlockContent>(contents); boolean changed; do { changed = false; int i = 0; while (i < largeContents.size()) { MenuBlockContent c = largeContents.get(i); if (avHeightUnits > c.getUnfilteredItemCount()) { changed = true; freeUnits -= c.getUnfilteredItemCount(); freeBlocksCount--; largeContents.remove(c); } else { i++; } } avHeightUnits = (double) freeUnits / freeBlocksCount; } while (changed); } else if (!even) { freeUnits = totalUnits - heightUnits; } for (int i = 0 ; i < contents.size() ; i++) { MenuBlockContent c = contents.get(i); int cs = preditor.getMenuCreator().getColorShift(c.getName()); int heightUnits; boolean isLast = (i == contents.size()-1); if (isLast) { heightUnits = unitsRest; } else if (even) { heightUnits = (int) ((double) freeUnits / freeBlocksCount + 0.999); freeUnits -= heightUnits; freeBlocksCount--; } else if (overfull) { if (avHeightUnits > c.getUnfilteredItemCount()) { heightUnits = c.getUnfilteredItemCount(); } else { heightUnits = (int) ((double) freeUnits / freeBlocksCount + 0.999); freeUnits -= heightUnits; freeBlocksCount--; } } else { int extraCols = (int) ((double) freeUnits / (contents.size() - i) + 0.999); heightUnits = c.getUnfilteredItemCount() + extraCols; freeUnits -= extraCols; } unitsRest -= heightUnits; MenuBlock mb = new MenuBlock(width, heightUnits * 15, cs, preditor); mb.setContent(c); column.add(mb); } return column; } /** * This method calculates the combined weight of two menu block columns. * * @param c1 Menu block column number 1. * @param c2 Menu block column number 2. * @return The combined weight. */ public static int getCombinedWeight(MenuBlockColumn c1, MenuBlockColumn c2) { int h = c1.heightUnits + c2.heightUnits; int s = c1.contents.size() + c2.contents.size(); return h * s; } }