/* * Licensed to The Apereo Foundation under one or more contributor license * agreements. See the NOTICE file distributed with this work for * additional information regarding copyright ownership. * * The Apereo Foundation licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * limitations under the License. * */ package org.unitime.timetable.gwt.client.solver.suggestions; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.TreeSet; import org.unitime.timetable.gwt.client.TimeHint; import org.unitime.timetable.gwt.client.rooms.RoomHint; import org.unitime.timetable.gwt.client.solver.SolverCookie; import org.unitime.timetable.gwt.client.solver.DataTable.DataTableCell; import org.unitime.timetable.gwt.client.widgets.P; import org.unitime.timetable.gwt.client.widgets.UniTimeTable; import org.unitime.timetable.gwt.client.widgets.UniTimeTableHeader; import org.unitime.timetable.gwt.client.widgets.UniTimeTableHeader.HasColumnName; import org.unitime.timetable.gwt.client.widgets.UniTimeTableHeader.Operation; import org.unitime.timetable.gwt.resources.GwtConstants; import org.unitime.timetable.gwt.resources.GwtMessages; import org.unitime.timetable.gwt.resources.GwtResources; import org.unitime.timetable.gwt.shared.TableInterface; import org.unitime.timetable.gwt.shared.SuggestionsInterface.ClassAssignmentDetails; import org.unitime.timetable.gwt.shared.SuggestionsInterface.RoomInfo; import org.unitime.timetable.gwt.shared.SuggestionsInterface.Suggestion; import org.unitime.timetable.gwt.shared.SuggestionsInterface.SuggestionProperties; import org.unitime.timetable.gwt.shared.SuggestionsInterface.TimeInfo; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style.TextDecoration; import com.google.gwt.event.dom.client.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.event.dom.client.MouseOverEvent; import com.google.gwt.event.dom.client.MouseOverHandler; import com.google.gwt.i18n.client.NumberFormat; import com.google.gwt.user.client.TakesValue; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.client.ui.HasHorizontalAlignment.HorizontalAlignmentConstant; import com.google.gwt.user.client.ui.HasVerticalAlignment.VerticalAlignmentConstant; /** * @author Tomas Muller */ public class SuggestionsTable extends UniTimeTable<Suggestion> implements TakesValue<Collection<Suggestion>>{ protected static final GwtMessages MESSAGES = GWT.create(GwtMessages.class); protected static final GwtConstants CONSTANTS = GWT.create(GwtConstants.class); protected static final GwtResources RESOURCES = GWT.create(GwtResources.class); public static NumberFormat sDF = NumberFormat.getFormat("0.###"); private SuggestionProperties iProperties; private boolean iSuggestions; private SuggestionColumn iSortBy = null; private boolean iAsc = true; public SuggestionsTable(SuggestionProperties properties, boolean suggestions) { addStyleName("unitime-ClassAssignmentTable"); addStyleName("unitime-ClassAssignmentTableSuggestions"); iProperties = properties; iSuggestions = suggestions; List<UniTimeTableHeader> header = new ArrayList<UniTimeTableHeader>(); for (SuggestionColumn column: SuggestionColumn.values()) { int nrCells = getNbrCells(column); for (int idx = 0; idx < nrCells; idx++) { UniTimeTableHeader h = new UniTimeTableHeader(getColumnName(column, idx), getColumnAlignment(column, idx)); header.add(h); } } for (final SuggestionColumn column: SuggestionColumn.values()) { if (SuggestionsComparator.isApplicable(column) && getNbrCells(column) > 0) { final UniTimeTableHeader h = header.get(getCellIndex(column)); Operation op = new SortOperation() { @Override public void execute() { doSort(column); } @Override public boolean isApplicable() { return getRowCount() > 1 && h.isVisible(); } @Override public boolean hasSeparator() { return false; } @Override public String getName() { return MESSAGES.opSortBy(getColumnName()); } @Override public String getColumnName() { return h.getHTML().replace("<br>", " "); } }; h.addOperation(op); } } addRow(null, header); for (int i = 0; i < getCellCount(0); i++) getCellFormatter().setStyleName(0, i, "unitime-ClickableTableHeader"); setSortBy(iSuggestions ? SolverCookie.getInstance().getSuggestionsSort() : SolverCookie.getInstance().getPlacementsSort()); } protected void doSort(SuggestionColumn column) { if (column == iSortBy) { iAsc = !iAsc; } else { iSortBy = column; iAsc = true; } if (iSuggestions) SolverCookie.getInstance().setSuggestionsSort(getSortBy()); else SolverCookie.getInstance().setPlacementsSort(getSortBy()); sort(); } public boolean hasSortBy() { return iSortBy != null; } public int getSortBy() { return iSortBy == null ? 0 : iAsc ? 1 + iSortBy.ordinal() : -1 - iSortBy.ordinal(); } public void setSortBy(int sortBy) { if (sortBy == 0) { iSortBy = null; iAsc = true; } else if (sortBy > 0) { iSortBy = SuggestionColumn.values()[sortBy - 1]; iAsc = true; } else { iSortBy = SuggestionColumn.values()[-1 - sortBy]; iAsc = false; } sort(); } public void sort() { if (iSortBy == null) return; if (getNbrCells(iSortBy) == 0) iSortBy = SuggestionColumn.SCORE; UniTimeTableHeader header = getHeader(getCellIndex(iSortBy)); sort(header, new SuggestionsComparator(iProperties.getFirstDay(), iSortBy, true), iAsc); } public static enum SuggestionColumn { SCORE, CLASS, DATE, TIME, ROOM, STUDENTS, OBJECTIVES, ; } protected int getNbrCells(SuggestionColumn column) { switch (column) { default: return 1; } } public String getColumnName(SuggestionColumn column, int idx) { switch (column) { case SCORE: return MESSAGES.colScore(); case CLASS: return MESSAGES.colClass(); case DATE: return MESSAGES.colDate(); case TIME: return MESSAGES.colTime(); case ROOM: return MESSAGES.colRoom(); case STUDENTS: return MESSAGES.colStudents(); case OBJECTIVES: return MESSAGES.colObjectives(); default: return column.name(); } } protected HorizontalAlignmentConstant getColumnAlignment(SuggestionColumn column, int idx) { switch (column) { default: return HasHorizontalAlignment.ALIGN_LEFT; } } protected int getCellIndex(SuggestionColumn column) { int ret = 0; for (SuggestionColumn c: SuggestionColumn.values()) if (c.ordinal() < column.ordinal()) ret += getNbrCells(c); return ret; } protected Widget getCellLine(final ClassAssignmentDetails details, boolean conflict, final SuggestionColumn column, final int idx) { switch (column) { case CLASS: P classLabel = new P("label"); classLabel.setText(details.getClazz().getName()); if (details.getClazz().getPref() != null) classLabel.getElement().getStyle().setColor(iProperties.getPreference(details.getClazz().getPref()).getColor()); return classLabel; case DATE: P date = new P("date"); if (details.getTime() != null) { P current = new P("old"); current.setText(details.getTime().getDatePatternName()); if (details.getTime().getDatePatternPreference() != 0) current.getElement().getStyle().setColor(iProperties.getPreference(details.getTime().getDatePatternPreference()).getColor()); if (details.getTime().isStriked()) current.getElement().getStyle().setTextDecoration(TextDecoration.LINE_THROUGH); date.add(current); if (details.getAssignedTime() == null) { // P arrow = new P("arrow"); arrow.setHTML(MESSAGES.assignmentArrow()); date.add(arrow); // P notAssigned = new P("not-assigned"); notAssigned.setText(MESSAGES.unassignment()); date.add(notAssigned); } else if (!details.getAssignedTime().getDatePatternName().equals(details.getTime().getDatePatternName())) { P arrow = new P("arrow"); arrow.setHTML(MESSAGES.assignmentArrow()); date.add(arrow); P other = new P("new"); other.setText(details.getAssignedTime().getDatePatternName()); if (details.getAssignedTime().getDatePatternPreference() != 0) other.getElement().getStyle().setColor(iProperties.getPreference(details.getAssignedTime().getDatePatternPreference()).getColor()); if (details.getAssignedTime().isStriked()) other.getElement().getStyle().setTextDecoration(TextDecoration.LINE_THROUGH); date.add(other); } } else if (details.getAssignedTime() != null) { P other = new P("new"); other.setText(details.getAssignedTime().getDatePatternName()); if (details.getAssignedTime().getDatePatternPreference() != 0) other.getElement().getStyle().setColor(iProperties.getPreference(details.getAssignedTime().getDatePatternPreference()).getColor()); if (details.getAssignedTime().isStriked()) other.getElement().getStyle().setTextDecoration(TextDecoration.LINE_THROUGH); date.add(other); } return date; case TIME: P time = new P("time"); if (details.getTime() != null) { final P current = new P("old"); current.setText(details.getTime().getName(iProperties.getFirstDay(), false, CONSTANTS)); if (details.getTime().getPref() != 0) current.getElement().getStyle().setColor(iProperties.getPreference(details.getTime().getPref()).getColor()); if (details.getTime().isStriked()) current.getElement().getStyle().setTextDecoration(TextDecoration.LINE_THROUGH); final String timeHint = details.getClazz().getClassId() + "," + details.getTime().getDays() + "," + details.getTime().getStartSlot(); current.addMouseOverHandler(new MouseOverHandler() { @Override public void onMouseOver(MouseOverEvent e) { TimeHint.showHint(current.getElement(), timeHint); } }); current.addMouseOutHandler(new MouseOutHandler() { @Override public void onMouseOut(MouseOutEvent e) { TimeHint.hideHint(); } }); time.add(current); if (details.getAssignedTime() == null) { P arrow = new P("arrow"); arrow.setHTML(MESSAGES.assignmentArrow()); time.add(arrow); P notAssigned = new P("not-assigned"); notAssigned.setText(MESSAGES.unassignment()); time.add(notAssigned); } else if (details.getAssignedTime().getStartSlot() != details.getTime().getStartSlot() || details.getAssignedTime().getDays() != details.getTime().getDays() || !details.getAssignedTime().getPatternId().equals(details.getTime().getPatternId())) { P arrow = new P("arrow"); arrow.setHTML(MESSAGES.assignmentArrow()); time.add(arrow); final P other = new P("new"); other.setText(details.getAssignedTime().getName(iProperties.getFirstDay(), false, CONSTANTS)); if (details.getAssignedTime().getPref() != 0) other.getElement().getStyle().setColor(iProperties.getPreference(details.getAssignedTime().getPref()).getColor()); if (details.getAssignedTime().isStriked()) other.getElement().getStyle().setTextDecoration(TextDecoration.LINE_THROUGH); final String otherTimeHint = details.getClazz().getClassId() + "," + details.getAssignedTime().getDays() + "," + details.getAssignedTime().getStartSlot(); other.addMouseOverHandler(new MouseOverHandler() { @Override public void onMouseOver(MouseOverEvent e) { TimeHint.showHint(other.getElement(), otherTimeHint); } }); other.addMouseOutHandler(new MouseOutHandler() { @Override public void onMouseOut(MouseOutEvent e) { TimeHint.hideHint(); } }); time.add(other); } } else if (details.getAssignedTime() != null) { final P other = new P("new"); other.setText(details.getAssignedTime().getName(iProperties.getFirstDay(), false, CONSTANTS)); if (details.getAssignedTime().getPref() != 0) other.getElement().getStyle().setColor(iProperties.getPreference(details.getAssignedTime().getPref()).getColor()); if (details.getAssignedTime().isStriked()) other.getElement().getStyle().setTextDecoration(TextDecoration.LINE_THROUGH); final String otherTimeHint = details.getClazz().getClassId() + "," + details.getAssignedTime().getDays() + "," + details.getAssignedTime().getStartSlot(); other.addMouseOverHandler(new MouseOverHandler() { @Override public void onMouseOver(MouseOverEvent e) { TimeHint.showHint(other.getElement(), otherTimeHint); } }); other.addMouseOutHandler(new MouseOutHandler() { @Override public void onMouseOut(MouseOutEvent e) { TimeHint.hideHint(); } }); time.add(other); } return time; case ROOM: P rooms = new P("rooms"); if (details.getRoom() != null) { for (int i = 0; i < details.getRoom().size(); i++) { final RoomInfo r = details.getRoom().get(i); P room = new P("room"); final P current = new P("old"); current.setText(r.getName()); if (r.getPref() != 0) current.getElement().getStyle().setColor(iProperties.getPreference(r.getPref()).getColor()); if (r.isStriked()) current.getElement().getStyle().setTextDecoration(TextDecoration.LINE_THROUGH); if (r.getId() != null) { current.addMouseOverHandler(new MouseOverHandler() { @Override public void onMouseOver(MouseOverEvent e) { RoomHint.showHint(current.getElement(), r.getId(), null, null, true); } }); current.addMouseOutHandler(new MouseOutHandler() { @Override public void onMouseOut(MouseOutEvent e) { RoomHint.hideHint(); } }); } room.add(current); if (details.getAssignedRoom() != null && i < details.getAssignedRoom().size()) { final RoomInfo q = details.getAssignedRoom().get(i); if (!q.getId().equals(r.getId())) { P arrow = new P("arrow"); arrow.setHTML(MESSAGES.assignmentArrow()); room.add(arrow); final P other = new P("new"); other.setText(q.getName()); if (q.getPref() != 0) other.getElement().getStyle().setColor(iProperties.getPreference(q.getPref()).getColor()); if (q.isStriked()) other.getElement().getStyle().setTextDecoration(TextDecoration.LINE_THROUGH); if (q.getId() != null) { other.addMouseOverHandler(new MouseOverHandler() { @Override public void onMouseOver(MouseOverEvent e) { RoomHint.showHint(other.getElement(), q.getId(), null, null, true); } }); other.addMouseOutHandler(new MouseOutHandler() { @Override public void onMouseOut(MouseOutEvent e) { RoomHint.hideHint(); } }); } room.add(other); } } else { P arrow = new P("arrow"); arrow.setHTML(MESSAGES.assignmentArrow()); room.add(arrow); P notAssigned = new P("not-assigned"); notAssigned.setText(MESSAGES.unassignment()); room.add(notAssigned); } if (i + 1 < details.getRoom().size()) { P separator = new P("separator"); separator.setText(CONSTANTS.itemSeparator()); rooms.add(separator); room.add(separator); } rooms.add(room); } } else if (details.getAssignedRoom() != null) { for (int i = 0; i < details.getAssignedRoom().size(); i++) { final RoomInfo q = details.getAssignedRoom().get(i); P room = new P("room"); final P other = new P("new"); other.setText(q.getName()); if (q.getPref() != 0) other.getElement().getStyle().setColor(iProperties.getPreference(q.getPref()).getColor()); if (q.isStriked()) other.getElement().getStyle().setTextDecoration(TextDecoration.LINE_THROUGH); if (q.getId() != null) { other.addMouseOverHandler(new MouseOverHandler() { @Override public void onMouseOver(MouseOverEvent e) { RoomHint.showHint(other.getElement(), q.getId(), null, null, true); } }); other.addMouseOutHandler(new MouseOutHandler() { @Override public void onMouseOut(MouseOutEvent e) { RoomHint.hideHint(); } }); } room.add(other); if (i + 1 < details.getAssignedRoom().size()) { P separator = new P("separator"); separator.setText(CONSTANTS.itemSeparator()); rooms.add(separator); room.add(separator); } rooms.add(room); } } return rooms; default: return null; } } protected Widget getCell(final Suggestion suggestion, final SuggestionColumn column, final int idx) { switch (column) { case SCORE: return new HTML(dispNumber(suggestion.getValue() - suggestion.getBaseValue())); case CLASS: P classes = new P("classes"); if (suggestion.hasDifferentAssignments()) for (ClassAssignmentDetails details: suggestion.getDifferentAssignments()) classes.add(getCellLine(details, false, column, idx)); if (suggestion.hasUnresolvedConflicts()) for (ClassAssignmentDetails details: suggestion.getUnresolvedConflicts()) classes.add(getCellLine(details, true, column, idx)); return classes; case DATE: P dates = new P("dates"); if (suggestion.hasDifferentAssignments()) for (ClassAssignmentDetails details: suggestion.getDifferentAssignments()) dates.add(getCellLine(details, false, column, idx)); if (suggestion.hasUnresolvedConflicts()) for (ClassAssignmentDetails details: suggestion.getUnresolvedConflicts()) dates.add(getCellLine(details, true, column, idx)); return dates; case TIME: P times = new P("times"); if (suggestion.hasDifferentAssignments()) for (ClassAssignmentDetails details: suggestion.getDifferentAssignments()) times.add(getCellLine(details, false, column, idx)); if (suggestion.hasUnresolvedConflicts()) for (ClassAssignmentDetails details: suggestion.getUnresolvedConflicts()) times.add(getCellLine(details, true, column, idx)); return times; case ROOM: P rooms = new P("rooms"); if (suggestion.hasDifferentAssignments()) for (ClassAssignmentDetails details: suggestion.getDifferentAssignments()) rooms.add(getCellLine(details, false, column, idx)); if (suggestion.hasUnresolvedConflicts()) for (ClassAssignmentDetails details: suggestion.getUnresolvedConflicts()) rooms.add(getCellLine(details, true, column, idx)); return rooms; case STUDENTS: return (suggestion.hasStudentConflictSummary() ? new DataTableCell(null, suggestion.getStudentConflictSummary()) : null); case OBJECTIVES: return new Objectives(suggestion); default: return null; } } public int addRow(final Suggestion suggestion) { List<Widget> widgets = new ArrayList<Widget>(); for (SuggestionColumn column: SuggestionColumn.values()) { int nbrCells = getNbrCells(column); for (int idx = 0; idx < nbrCells; idx ++) { Widget cell = getCell(suggestion, column, idx); if (cell == null) cell = new P(); widgets.add(cell); } } int row = addRow(suggestion, widgets); getRowFormatter().setStyleName(row, "row"); for (int col = 0; col < getCellCount(row); col++) getCellFormatter().setStyleName(row, col, "cell"); return row; } public static class SuggestionsComparator implements Comparator<Suggestion> { private Integer iFirstDay; private SuggestionColumn iColumn; private boolean iAsc; public SuggestionsComparator(Integer firstDay, SuggestionColumn column, boolean asc) { iFirstDay = firstDay; iColumn = column; iAsc = asc; } public int compareById(ClassAssignmentDetails c1, ClassAssignmentDetails c2) { return compare(c1.getClazz().getClassId(), c2.getClazz().getClassId()); } public int compareByName(ClassAssignmentDetails c1, ClassAssignmentDetails c2) { return c1.getClazz().compareTo(c2.getClazz()); } public int compareByDate(TimeInfo t1, TimeInfo t2) { return compare(t1 == null ? null : t1.getDatePatternName(), t2 == null ? null : t2.getDatePatternName()); } public int compareByTime(TimeInfo t1, TimeInfo t2) { int cmp = compare(t1 == null ? null : t1.getDaysOrder(iFirstDay), t2 == null ? null : t2.getDaysOrder(iFirstDay)); if (cmp != 0) return cmp; cmp = compare(t1 == null ? null : t1.getStartSlot(), t2 == null ? null : t2.getStartSlot()); if (cmp != 0) return cmp; return compare(t1 == null ? null : t1.getName(iFirstDay, false, CONSTANTS), t2 == null ? null : t2.getName(iFirstDay, false, CONSTANTS)); } public int compareByRoom(List<RoomInfo> r1, List<RoomInfo> r2) { int c1 = (r1 == null ? 0 : r1.size()); int c2 = (r2 == null ? 0 : r2.size()); if (c1 != c2) return c1 < c2 ? -1 : 1; for (int i = 0; i < c1; i++) { int cmp = compare(r1.get(i).getName(), r2.get(i).getName()); if (cmp != 0) return cmp; } return 0; } public int compareByCell(TableInterface.TableCellInterface c1, TableInterface.TableCellInterface c2) { if (c1 == null) return (c2 == null ? 0 : -1); if (c2 == null) return 1; return c1.compareTo(c2); } protected int compareByColumn(ClassAssignmentDetails c1, ClassAssignmentDetails c2) { switch (iColumn) { case CLASS: return compareByName(c1, c2); case DATE: return compareByDate(c1.getAssignedTime() == null ? c1.getTime() : c1.getAssignedTime(), c2.getAssignedTime() == null ? c2.getTime() : c2.getAssignedTime()); case TIME: return compareByTime(c1.getAssignedTime() == null ? c1.getTime() : c1.getAssignedTime(), c2.getAssignedTime() == null ? c2.getTime() : c2.getAssignedTime()); case ROOM: return compareByRoom(c1.getAssignedRoom() == null ? c1.getRoom() : c1.getAssignedRoom(), c2.getAssignedRoom() == null ? c2.getRoom() : c2.getAssignedRoom()); default: return compareByName(c1, c2); } } protected int compareByColumns(List<ClassAssignmentDetails> l1, List<ClassAssignmentDetails> l2) { if (l1 == null) { return (l2 == null ? 0 : -1); } else { if (l2 == null) return 1; Iterator<ClassAssignmentDetails> i1 = l1.iterator(); Iterator<ClassAssignmentDetails> i2 = l2.iterator(); while (i1.hasNext() && i2.hasNext()) { return compareByColumn(i1.next(), i2.next()); } return (i1.hasNext() ? 1 : -1); } } public int compareByScore(Suggestion s1, Suggestion s2) { return Double.compare(s1.getValue(), s2.getValue()); } public static boolean isApplicable(SuggestionColumn column) { switch (column) { case SCORE: case CLASS: case DATE: case TIME: case ROOM: case STUDENTS: return true; default: return false; } } @Override public int compare(Suggestion s1, Suggestion s2) { if (iColumn == SuggestionColumn.SCORE) { int cmp = compareByScore(s1, s2); if (cmp != 0) return (iAsc ? cmp : -cmp); } if (iColumn == SuggestionColumn.STUDENTS) { int cmp = compareByCell(s1.getStudentConflictSummary(), s2.getStudentConflictSummary()); if (cmp != 0) return (iAsc ? cmp : -cmp); cmp = compareByScore(s1, s2); if (cmp != 0) return (iAsc ? cmp : -cmp); } int cmp = compareByColumns(s1.getDifferentAssignments(), s2.getDifferentAssignments()); if (cmp == 0) cmp = compareByColumns(s1.getUnresolvedConflicts(), s2.getUnresolvedConflicts()); if (cmp == 0) cmp = s1.compareTo(s2); return (iAsc ? cmp : -cmp); } protected int compare(String s1, String s2) { if (s1 == null || s1.isEmpty()) { return (s2 == null || s2.isEmpty() ? 0 : 1); } else { return (s2 == null || s2.isEmpty() ? -1 : s1.compareToIgnoreCase(s2)); } } protected int compare(Number n1, Number n2) { return (n1 == null ? n2 == null ? 0 : -1 : n2 == null ? 1 : Double.compare(n1.doubleValue(), n2.doubleValue())); } protected int compare(Boolean b1, Boolean b2) { return (b1 == null ? b2 == null ? 0 : -1 : b2 == null ? 1 : (b1.booleanValue() == b2.booleanValue()) ? 0 : (b1.booleanValue() ? 1 : -1)); } } public static interface SortOperation extends Operation, HasColumnName {} public static String dispNumber(int number) { return dispNumber("",number); } public static String dispNumber(String prefix, int number) { if (number>0) return "<font color='red'>"+prefix+"+"+number+"</font>"; if (number<0) return "<font color='green'>"+prefix+number+"</font>"; return prefix+"0"; } public static String dispNumberShort(boolean rem, int n1, int n2) { if (n1==0 && n2==0) return ""; if (rem) return dispNumber(-n1); int dif = n2-n1; if (dif==0) return n1+"→"+n2; else if (dif<0) return "<font color='green'>"+n1+"→"+n2+"</font>"; else return "<font color='red'>"+n1+"→"+n2+"</font>"; } public static String dispNumber(String prefix, double number) { if (number>0) return "<font color='red'>"+prefix+"+"+sDF.format(number)+"</font>"; if (number<0) return "<font color='green'>"+prefix+sDF.format(number)+"</font>"; return prefix+"0"; } public static String dispNumberShort(boolean rem, double n1, double n2) { return dispNumberShort(rem,"",n1,n2); } public static String dispNumberShort(boolean rem, String prefix, double n1, double n2) { if (n1==0 && n2==0) return ""; if (rem) return dispNumber(prefix,-n1); double dif = n2-n1; if (dif==0) return prefix+sDF.format(n1)+"→"+sDF.format(n2); else if (dif<0) return "<font color='green'>"+prefix+sDF.format(n1)+"→"+sDF.format(n2)+"</font>"; else return "<font color='red'>"+prefix+sDF.format(n1)+"→"+sDF.format(n2)+"</font>"; } public static String dispNumber(int n1, int n2) { return dispNumber(n1-n2);//+" ("+n2+(n1==n2?"":" → "+n1)+")"; } public static String dispNumber(double n1, double n2) { return dispNumber(n1-n2);//+" ("+sDF.format(n2)+(n1==n2?"":" → "+sDF.format(n1))+")"; } public static String dispNumber(double number) { return dispNumber("",number); } @Override public Collection<Suggestion> getValue() { return getData(); } @Override public void setValue(Collection<Suggestion> value) { clearTable(1); if (value != null) for (Suggestion suggestion: value) addRow(suggestion); sort(); } protected static class Objectives extends P implements HasVerticalCellAlignment { Objectives(Suggestion suggestion) { super("objectives"); if (suggestion.getCriteria() != null) { for (String criterion: new TreeSet<String>(suggestion.getCriteria().keySet())) { double value = suggestion.getCriterion(criterion); double base = suggestion.getBaseCriterion(criterion); if (Math.abs(value - base) >= 0.001) { P obj = new P("objective"); obj.setHTML(criterion + ": " + dispNumber(value, base)); add(obj); } } } } @Override public VerticalAlignmentConstant getVerticalCellAlignment() { return HasVerticalAlignment.ALIGN_MIDDLE; } } }