// 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.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import nextapp.echo.app.event.ActionEvent;
import nextapp.echo.app.event.ActionListener;
/**
* This class represents the content of a menu block. The content consists of menu items.
*
* @author Tobias Kuhn
*/
class MenuBlockContent implements ActionListener {
private static final long serialVersionUID = 2320151987455571216L;
private List<MenuItem> items = new ArrayList<MenuItem>();
private TreeMap<String, MenuEntry> entryMap = new TreeMap<String, MenuEntry>();
private Collection<MenuEntry> filteredEntries = entryMap.values();
private Map<String, MenuItem> idMap = new HashMap<String, MenuItem>();
private String name;
private String filter = "";
private boolean isSorted = true;
private Comparator<MenuItem> comparator;
private ActionListener actionListener;
/**
* Creates a new menu block content object.
*
* @param name The name of the menu block.
*/
public MenuBlockContent(String name) {
this.name = name;
}
/**
* Sets the comparator to be used to sort the menu items.
*
* @param comparator The comparator.
*/
public void setComparator(Comparator<MenuItem> comparator) {
this.comparator = comparator;
}
/**
* Sets the action listener
*
* @param newActionListener The action listener.
*/
public void setActionListener(ActionListener newActionListener) {
for (MenuItem m : items) {
if (m instanceof MenuEntry) {
if (actionListener != null) {
m.removeActionListener(actionListener);
}
if (newActionListener != null) {
m.addActionListener(newActionListener);
}
}
}
actionListener = newActionListener;
}
/**
* Add the menu items.
*
* @param items The menu items to be added.
*/
public void addItems(List<MenuItem> items) {
for (MenuItem item : items) {
addItem(item);
}
}
/**
* Adds the menu item.
*
* @param item The menu item to be added.
*/
public void addItem(MenuItem item) {
String id = item.getMenuItemID();
if (!(item instanceof MenuEntry && idMap.containsKey(id)) && !idMap.containsKey(id)) {
if (item instanceof MenuEntry) {
item.addActionListener(this);
}
items.add(item);
idMap.put(id, item);
if (item instanceof MenuEntry) {
MenuEntry entry = (MenuEntry) item;
entryMap.put(entry.getTextElement().getText().toLowerCase(), entry);
}
}
isSorted = false;
}
/**
* Returns the name of the menu block.
*
* @return The name of the menu block.
*/
public String getName() {
return name;
}
/**
* Returns true if the content is empty.
*
* @return true if the content is empty.
*/
public boolean isEmpty() {
return items.isEmpty();
}
/**
* Returns the number of items, regardless of the current filter.
*
* @return The number of items.
*/
public int getUnfilteredItemCount() {
return items.size();
}
/**
* Returns all menu items that are menu entries.
*
* @return A list of all menu entries.
*/
public List<MenuEntry> getEntries() {
return new ArrayList<MenuEntry>(filteredEntries);
}
/**
* Returns the number of menu entries (after filtering).
*
* @return The number of menu entries.
*/
public int getEntryCount() {
return filteredEntries.size();
}
/**
* Returns all menu items.
*
* @return A list of all menu items.
*/
public List<MenuItem> getItems() {
// TODO improve this method
if (!isSorted && comparator != null) {
Collections.sort(items, comparator);
}
if (filter.length() == 0) {
return items;
}
List<MenuItem> filteredItems = new ArrayList<MenuItem>();
for (MenuItem item : items) {
if (item instanceof MenuEntry) {
// TODO this is not so nice:
if (((MenuEntry) item).getTextElement().getText().toLowerCase().startsWith(filter)) {
filteredItems.add(item);
}
} else {
filteredItems.add(item);
}
}
return filteredItems;
}
/**
* Returns the menu entry with the given text or null if no such entry exists. If there are
* more than one matching entry then the first of them is returned. The look-up is not case
* sensitive.
*
* @param entryText The text of the menu entry to look for.
* @return The menu entry.
*/
public MenuEntry getEntry(String entryText) {
return entryMap.get(entryText.toLowerCase());
}
/**
* Returns a common string with maximal size such that each menu entry starts with the string.
* E.g. "ar" is returned if the menu entries are "architect", "archive" and "artist".
*
* @return The common start string.
*/
public String getStartString() {
String startString = null;
for (MenuEntry entry : getEntries()) {
String c = entry.getTextElement().getText().toLowerCase();
if (startString == null) {
startString = c;
} else {
for (int i = startString.length(); i >= 0; i--) {
if (c.startsWith(startString.substring(0, i))) break;
startString = startString.substring(0, i-1);
}
}
}
return startString;
}
/**
* Sets the filter. All entries that do not start with the given filter string become
* invisible.
*
* @param filter The filter string.
*/
public void setFilter(String filter) {
if (filter == null || filter.length() == 0) {
this.filter = "";
filteredEntries = entryMap.values();
} else {
this.filter = filter.toLowerCase();
// TODO find a better way to do this without using "°":
filteredEntries = entryMap.subMap(this.filter, this.filter + "°").values();
}
}
public void actionPerformed(ActionEvent ev) {
if (actionListener != null) {
actionListener.actionPerformed(ev);
}
}
}