001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.dialogs; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005import static org.openstreetmap.josm.tools.I18n.trc; 006 007import java.awt.Graphics2D; 008import java.util.Collection; 009import java.util.List; 010 011import javax.swing.table.AbstractTableModel; 012 013import org.openstreetmap.josm.data.osm.Filter; 014import org.openstreetmap.josm.data.osm.FilterModel; 015import org.openstreetmap.josm.data.osm.OsmPrimitive; 016import org.openstreetmap.josm.gui.MainApplication; 017import org.openstreetmap.josm.gui.MapFrame; 018import org.openstreetmap.josm.gui.autofilter.AutoFilterManager; 019import org.openstreetmap.josm.gui.widgets.OSDLabel; 020import org.openstreetmap.josm.tools.Logging; 021 022/** 023 * The model that is used for the table in the {@link FilterDialog}. 024 * 025 * @author Petr_DlouhĂ˝ 026 */ 027public class FilterTableModel extends AbstractTableModel { 028 029 /** 030 * The filter enabled column 031 */ 032 public static final int COL_ENABLED = 0; 033 /** 034 * The column indicating if the filter is hiding. 035 */ 036 public static final int COL_HIDING = 1; 037 /** 038 * The column that displays the filter text 039 */ 040 public static final int COL_TEXT = 2; 041 /** 042 * The column to invert the filter 043 */ 044 public static final int COL_INVERTED = 3; 045 046 /** 047 * The filter model 048 */ 049 final FilterModel model = new FilterModel(); 050 051 /** 052 * A helper for {@link #drawOSDText(Graphics2D)}. 053 */ 054 private final OSDLabel lblOSD = new OSDLabel(""); 055 056 /** 057 * Constructs a new {@code FilterTableModel}. 058 */ 059 public FilterTableModel() { 060 loadPrefs(); 061 } 062 063 private void updateFilters() { 064 AutoFilterManager.getInstance().setCurrentAutoFilter(null); 065 executeFilters(true); 066 } 067 068 /** 069 * Runs the filters on the current edit data set, if any. Does nothing if no filter is enabled. 070 */ 071 public void executeFilters() { 072 executeFilters(false); 073 } 074 075 /** 076 * Runs the filter on a list of primitives that are part of the edit data set, if any. Does nothing if no filter is enabled. 077 * @param primitives The primitives 078 */ 079 public void executeFilters(Collection<? extends OsmPrimitive> primitives) { 080 executeFilters(primitives, false); 081 } 082 083 /** 084 * Runs the filters on the current edit data set, if any. 085 * @param force force execution of filters even if no filter is enabled. Useful to reset state after change of filters 086 * @since 14206 087 */ 088 public void executeFilters(boolean force) { 089 if (AutoFilterManager.getInstance().getCurrentAutoFilter() == null && (force || model.hasFilters())) { 090 model.executeFilters(); 091 updateMap(); 092 } 093 } 094 095 /** 096 * Runs the filter on a list of primitives that are part of the edit data set, if any. 097 * @param force force execution of filters even if no filter is enabled. Useful to reset state after change of filters 098 * @param primitives The primitives 099 * @since 14206 100 */ 101 public void executeFilters(Collection<? extends OsmPrimitive> primitives, boolean force) { 102 if (AutoFilterManager.getInstance().getCurrentAutoFilter() == null && (force || model.hasFilters())) { 103 model.executeFilters(primitives); 104 updateMap(); 105 } 106 } 107 108 private void updateMap() { 109 MapFrame map = MainApplication.getMap(); 110 if (map != null && model.isChanged()) { 111 map.filterDialog.updateDialogHeader(); 112 } 113 } 114 115 private void loadPrefs() { 116 model.loadPrefs("filters.entries"); 117 } 118 119 private void savePrefs() { 120 model.savePrefs("filters.entries"); 121 } 122 123 /** 124 * Adds a new filter to the filter list. 125 * @param filter The new filter 126 */ 127 public void addFilter(Filter filter) { 128 if (model.addFilter(filter)) { 129 savePrefs(); 130 updateFilters(); 131 int size = model.getFiltersCount(); 132 fireTableRowsInserted(size - 1, size - 1); 133 } 134 } 135 136 /** 137 * Moves down the filter in the given row. 138 * @param rowIndex The filter row 139 */ 140 public void moveDownFilter(int rowIndex) { 141 if (model.moveDownFilter(rowIndex)) { 142 savePrefs(); 143 updateFilters(); 144 fireTableRowsUpdated(rowIndex, rowIndex + 1); 145 } 146 } 147 148 /** 149 * Moves up the filter in the given row 150 * @param rowIndex The filter row 151 */ 152 public void moveUpFilter(int rowIndex) { 153 if (model.moveUpFilter(rowIndex)) { 154 savePrefs(); 155 updateFilters(); 156 fireTableRowsUpdated(rowIndex - 1, rowIndex); 157 } 158 } 159 160 /** 161 * Removes the filter that is displayed in the given row 162 * @param rowIndex The index of the filter to remove 163 */ 164 public void removeFilter(int rowIndex) { 165 if (model.removeFilter(rowIndex) != null) { 166 savePrefs(); 167 updateFilters(); 168 fireTableRowsDeleted(rowIndex, rowIndex); 169 } 170 } 171 172 /** 173 * Sets/replaces the filter for a given row. 174 * @param rowIndex The row index 175 * @param filter The filter that should be placed in that row 176 */ 177 public void setFilter(int rowIndex, Filter filter) { 178 model.setFilter(rowIndex, filter); 179 savePrefs(); 180 updateFilters(); 181 fireTableRowsUpdated(rowIndex, rowIndex); 182 } 183 184 /** 185 * Gets the filter by row index 186 * @param rowIndex The row index 187 * @return The filter in that row 188 */ 189 public Filter getFilter(int rowIndex) { 190 return model.getFilter(rowIndex); 191 } 192 193 @Override 194 public int getRowCount() { 195 return model.getFiltersCount(); 196 } 197 198 @Override 199 public int getColumnCount() { 200 return 5; 201 } 202 203 @Override 204 public String getColumnName(int column) { 205 String[] names = {/* translators notes must be in front */ 206 /* column header: enable filter */trc("filter", "E"), 207 /* column header: hide filter */trc("filter", "H"), 208 /* column header: filter text */trc("filter", "Text"), 209 /* column header: inverted filter */trc("filter", "I"), 210 /* column header: filter mode */trc("filter", "M")}; 211 return names[column]; 212 } 213 214 @Override 215 public Class<?> getColumnClass(int column) { 216 Class<?>[] classes = {Boolean.class, Boolean.class, String.class, Boolean.class, String.class}; 217 return classes[column]; 218 } 219 220 /** 221 * Determines if a cell is enabled. 222 * @param row row index 223 * @param column column index 224 * @return {@code true} if the cell at (row, column) is enabled 225 */ 226 public boolean isCellEnabled(int row, int column) { 227 return model.getFilter(row).enable || column == 0; 228 } 229 230 @Override 231 public boolean isCellEditable(int row, int column) { 232 return column < 4 && isCellEnabled(row, column); 233 } 234 235 @Override 236 public void setValueAt(Object aValue, int row, int column) { 237 if (row >= model.getFiltersCount()) { 238 return; 239 } 240 Filter f = model.getFilter(row); 241 switch (column) { 242 case COL_ENABLED: 243 f.enable = (Boolean) aValue; 244 break; 245 case COL_HIDING: 246 f.hiding = (Boolean) aValue; 247 break; 248 case COL_TEXT: 249 f.text = (String) aValue; 250 break; 251 case COL_INVERTED: 252 f.inverted = (Boolean) aValue; 253 break; 254 default: // Do nothing 255 } 256 setFilter(row, f); 257 } 258 259 @Override 260 public Object getValueAt(int row, int column) { 261 if (row >= model.getFiltersCount()) { 262 return null; 263 } 264 Filter f = model.getFilter(row); 265 switch (column) { 266 case COL_ENABLED: 267 return f.enable; 268 case COL_HIDING: 269 return f.hiding; 270 case COL_TEXT: 271 return f.text; 272 case COL_INVERTED: 273 return f.inverted; 274 case 4: 275 switch (f.mode) { /* translators notes must be in front */ 276 case replace: /* filter mode: replace */ 277 return trc("filter", "R"); 278 case add: /* filter mode: add */ 279 return trc("filter", "A"); 280 case remove: /* filter mode: remove */ 281 return trc("filter", "D"); 282 case in_selection: /* filter mode: in selection */ 283 return trc("filter", "F"); 284 default: 285 Logging.warn("Unknown filter mode: " + f.mode); 286 } 287 break; 288 default: // Do nothing 289 } 290 return null; 291 } 292 293 /** 294 * Draws a text on the map display that indicates that filters are active. 295 * @param g The graphics to draw that text on. 296 */ 297 public void drawOSDText(Graphics2D g) { 298 model.drawOSDText(g, lblOSD, 299 tr("<h2>Filter active</h2>"), 300 tr("</p><p>Close the filter dialog to see all objects.<p></html>")); 301 } 302 303 /** 304 * Returns the list of filters. 305 * @return the list of filters 306 */ 307 public List<Filter> getFilters() { 308 return model.getFilters(); 309 } 310}