Ticket #15057: dialog-update-v3.patch
File dialog-update-v3.patch, 26.4 KB (added by , 7 years ago) |
---|
-
src/org/openstreetmap/josm/actions/OverpassDownloadAction.java
7 7 import java.awt.BorderLayout; 8 8 import java.awt.Component; 9 9 import java.awt.Dimension; 10 import java.awt.GridBagLayout; 10 11 import java.awt.event.ActionEvent; 11 12 import java.awt.event.FocusEvent; 12 13 import java.awt.event.FocusListener; … … 24 25 import javax.swing.JOptionPane; 25 26 import javax.swing.JPanel; 26 27 import javax.swing.JScrollPane; 28 import javax.swing.event.ListSelectionEvent; 29 import javax.swing.event.ListSelectionListener; 27 30 import javax.swing.plaf.basic.BasicArrowButton; 28 31 29 32 import org.openstreetmap.josm.Main; … … 39 42 import org.openstreetmap.josm.gui.widgets.JosmTextArea; 40 43 import org.openstreetmap.josm.io.OverpassDownloadReader; 41 44 import org.openstreetmap.josm.tools.GBC; 45 import org.openstreetmap.josm.tools.ImageProvider; 42 46 import org.openstreetmap.josm.tools.Shortcut; 43 47 44 48 /** … … 157 161 private static OverpassDownloadDialog instance; 158 162 private static final BooleanProperty OVERPASS_QUERY_LIST_OPENED = 159 163 new BooleanProperty("download.overpass.query-list.opened", false); 164 private static final String ACTION_IMG_SUBDIR = "dialogs"; 160 165 161 166 private OverpassDownloadDialog(Component parent) { 162 167 super(parent, ht("/Action/OverpassDownload")); … … 176 181 177 182 @Override 178 183 protected void buildMainPanelAboveDownloadSelections(JPanel pnl) { 179 // needed for the invisible checkboxes cbDownloadGpxData, cbDownloadNotes180 pnl.add(new JLabel(), GBC.eol());181 182 184 DisableActionsFocusListener disableActionsFocusListener = 183 185 new DisableActionsFocusListener(slippyMapChooser.getNavigationComponentActionMap()); 184 186 … … 190 192 } 191 193 }; 192 194 193 JButton openQueryWizard = new JButton( "Query Wizard");195 JButton openQueryWizard = new JButton(tr("Query Wizard")); 194 196 openQueryWizard.setToolTipText(tooltip); 195 197 openQueryWizard.addActionListener(queryWizardAction); 196 198 199 // use eol() that is needed for the invisible checkboxes cbDownloadGpxData, cbDownloadNotes 200 pnl.add(openQueryWizard, GBC.eol()); 201 pnl.add(new JLabel(tr("Overpass query:")), GBC.std().insets(5, 5, 0, 0).anchor(GBC.NORTHWEST)); 202 197 203 // CHECKSTYLE.OFF: LineLength 198 204 this.overpassQuery = new JosmTextArea( 199 205 "/*\n" + … … 215 221 } 216 222 }); 217 223 224 218 225 this.overpassQueryList = new OverpassQueryList(this, this.overpassQuery); 219 overpassQueryList.setToolTipText(tr("Show/hide Overpass snippet list")); 220 overpassQueryList.setVisible(OVERPASS_QUERY_LIST_OPENED.get()); 221 overpassQueryList.setPreferredSize(new Dimension(350, 300)); 226 this.overpassQueryList.setPreferredSize(new Dimension(350, 300)); 227 228 EditSnippetAction edit = new EditSnippetAction(); 229 RemoveSnippetAction remove = new RemoveSnippetAction(); 230 this.overpassQueryList.addSelectionListener(edit); 231 this.overpassQueryList.addSelectionListener(remove); 232 233 JPanel listPanel = new JPanel(new GridBagLayout()); 234 listPanel.add(new JLabel(tr("Your saved queries:")), GBC.eol().insets(2).anchor(GBC.CENTER)); 235 listPanel.add(this.overpassQueryList, GBC.eol().fill(GBC.BOTH)); 236 listPanel.add(new JButton(new AddSnippetAction()), GBC.std().fill(GBC.HORIZONTAL)); 237 listPanel.add(new JButton(edit), GBC.std().fill(GBC.HORIZONTAL)); 238 listPanel.add(new JButton(remove), GBC.std().fill(GBC.HORIZONTAL)); 239 listPanel.setVisible(OVERPASS_QUERY_LIST_OPENED.get()); 240 222 241 JScrollPane scrollPane = new JScrollPane(overpassQuery); 223 BasicArrowButton arrowButton = new BasicArrowButton( overpassQueryList.isVisible()242 BasicArrowButton arrowButton = new BasicArrowButton(listPanel.isVisible() 224 243 ? BasicArrowButton.EAST 225 244 : BasicArrowButton.WEST); 245 arrowButton.setToolTipText(tr("Show/hide Overpass snippet list")); 226 246 arrowButton.addActionListener(e -> { 227 if ( overpassQueryList.isVisible()) {228 overpassQueryList.setVisible(false);247 if (listPanel.isVisible()) { 248 listPanel.setVisible(false); 229 249 arrowButton.setDirection(BasicArrowButton.WEST); 230 250 OVERPASS_QUERY_LIST_OPENED.put(Boolean.FALSE); 231 251 } else { 232 overpassQueryList.setVisible(true);252 listPanel.setVisible(true); 233 253 arrowButton.setDirection(BasicArrowButton.EAST); 234 OVERPASS_QUERY_LIST_OPENED.put(Boolean. FALSE);254 OVERPASS_QUERY_LIST_OPENED.put(Boolean.TRUE); 235 255 } 236 256 }); 237 257 … … 241 261 242 262 JPanel pane = new JPanel(new BorderLayout()); 243 263 pane.add(innerPanel, BorderLayout.CENTER); 244 pane.add( overpassQueryList, BorderLayout.EAST);264 pane.add(listPanel, BorderLayout.EAST); 245 265 246 266 GBC gbc = GBC.eol().fill(GBC.HORIZONTAL); gbc.ipady = 200; 247 pnl.add(openQueryWizard, GBC.std().insets(5, 5, 5, 5));248 267 pnl.add(pane, gbc); 249 268 } 250 269 251 String getOverpassQuery() {270 public String getOverpassQuery() { 252 271 return overpassQuery.getText(); 253 272 } 254 273 … … 280 299 public void triggerDownload() { 281 300 super.btnDownload.doClick(); 282 301 } 302 303 /** 304 * Action that delegates snippet creation to {@link OverpassQueryList#createNewItem()}. 305 */ 306 class AddSnippetAction extends AbstractAction { 307 308 /** 309 * Constructs a new {@code AddSnippetAction}. 310 */ 311 AddSnippetAction() { 312 super(); 313 putValue(SMALL_ICON, ImageProvider.get(ACTION_IMG_SUBDIR, "add")); 314 putValue(SHORT_DESCRIPTION, tr("Add new snippet")); 315 } 316 317 @Override 318 public void actionPerformed(ActionEvent e) { 319 overpassQueryList.createNewItem(); 320 } 321 } 322 323 /** 324 * Action that delegates snippet removal to {@link OverpassQueryList#removeSelectedItem()}. 325 */ 326 class RemoveSnippetAction extends AbstractAction implements ListSelectionListener { 327 328 /** 329 * Constructs a new {@code RemoveSnippetAction}. 330 */ 331 RemoveSnippetAction() { 332 super(); 333 putValue(SMALL_ICON, ImageProvider.get(ACTION_IMG_SUBDIR, "delete")); 334 putValue(SHORT_DESCRIPTION, tr("Delete selected snippet")); 335 checkEnabled(); 336 } 337 338 @Override 339 public void actionPerformed(ActionEvent e) { 340 overpassQueryList.removeSelectedItem(); 341 } 342 343 /** 344 * Disables the action if no items are selected. 345 */ 346 void checkEnabled() { 347 setEnabled(overpassQueryList.getSelectedItem().isPresent()); 348 } 349 350 @Override 351 public void valueChanged(ListSelectionEvent e) { 352 checkEnabled(); 353 } 354 } 355 356 /** 357 * Action that delegates snippet edit to {@link OverpassQueryList#editSelectedItem()}. 358 */ 359 class EditSnippetAction extends AbstractAction implements ListSelectionListener { 360 361 /** 362 * Constructs a new {@code EditSnippetAction}. 363 */ 364 EditSnippetAction() { 365 super(); 366 putValue(SMALL_ICON, ImageProvider.get(ACTION_IMG_SUBDIR, "edit")); 367 putValue(SHORT_DESCRIPTION, tr("Edit selected snippet")); 368 checkEnabled(); 369 } 370 371 @Override 372 public void actionPerformed(ActionEvent e) { 373 overpassQueryList.editSelectedItem(); 374 } 375 376 /** 377 * Disables the action if no items are selected. 378 */ 379 void checkEnabled() { 380 setEnabled(overpassQueryList.getSelectedItem().isPresent()); 381 } 382 383 @Override 384 public void valueChanged(ListSelectionEvent e) { 385 checkEnabled(); 386 } 387 } 283 388 } 284 389 } -
src/org/openstreetmap/josm/actions/downloadtasks/PostDownloadHandler.java
19 19 import org.openstreetmap.josm.Main; 20 20 import org.openstreetmap.josm.gui.ExceptionDialogUtil; 21 21 import org.openstreetmap.josm.gui.Notification; 22 import org.openstreetmap.josm.gui.util.GuiHelper; 22 23 import org.openstreetmap.josm.tools.ExceptionUtil; 23 24 import org.openstreetmap.josm.tools.Utils; 24 25 … … 67 68 // make sure errors are reported only once 68 69 // 69 70 Set<Object> errors = new LinkedHashSet<>(task.getErrorObjects()); 71 70 72 if (this.errorReporter != null) { 71 errorReporter.accept(errors);73 GuiHelper.runInEDT(() -> errorReporter.accept(errors)); 72 74 } 73 75 74 76 if (errors.isEmpty()) { -
src/org/openstreetmap/josm/gui/download/OverpassQueryList.java
15 15 import java.awt.event.MouseEvent; 16 16 import java.time.LocalDateTime; 17 17 import java.time.format.DateTimeFormatter; 18 import java.time.format.DateTimeParseException; 18 19 import java.util.ArrayList; 19 20 import java.util.Collection; 20 21 import java.util.Collections; 21 22 import java.util.HashMap; 23 import java.util.List; 22 24 import java.util.Locale; 23 25 import java.util.Map; 24 26 import java.util.Objects; … … 73 75 */ 74 76 private static final String KEY_KEY = "key"; 75 77 private static final String QUERY_KEY = "query"; 76 private static final String USE_COUNT_KEY = "useCount";78 private static final String LAST_EDIT_KEY = "lastEdit"; 77 79 private static final String PREFERENCE_ITEMS = "download.overpass.query"; 78 80 81 private static final String TRANSLATED_HISTORY = tr("history"); 82 79 83 /** 80 84 * Constructs a new {@code OverpassQueryList}. 81 85 * @param parent The parent of this component. … … 102 106 */ 103 107 public synchronized Optional<SelectorItem> getSelectedItem() { 104 108 int idx = lsResult.getSelectedIndex(); 105 if (lsResultModel.getSize() == 0|| idx == -1) {109 if (lsResultModel.getSize() <= idx || idx == -1) { 106 110 return Optional.empty(); 107 111 } 108 112 109 113 SelectorItem item = lsResultModel.getElementAt(idx); 110 item.increaseUsageCount();111 114 112 this.items.values().stream()113 .filter(it -> !it.getKey().equals(item.getKey()))114 .forEach(SelectorItem::decreaseUsageCount);115 116 115 filterItems(); 117 116 118 117 return Optional.of(item); … … 127 126 */ 128 127 public synchronized void saveHistoricItem(String query) { 129 128 boolean historicExist = this.items.values().stream() 130 .filter(it -> it.getKey().contains("history"))131 129 .map(SelectorItem::getQuery) 132 130 .anyMatch(q -> q.equals(query)); 133 131 134 132 if (!historicExist) { 135 133 SelectorItem item = new SelectorItem( 136 "history " + LocalDateTime.now().format(FORMAT), 137 query); 134 TRANSLATED_HISTORY + " " + LocalDateTime.now().format(FORMAT), query); 138 135 139 136 this.items.put(item.getKey(), item); 140 137 … … 147 144 * Removes currently selected item, saves the current state to preferences and 148 145 * updates the view. 149 146 */ 150 p rivatesynchronized void removeSelectedItem() {147 public synchronized void removeSelectedItem() { 151 148 Optional<SelectorItem> it = this.getSelectedItem(); 152 149 153 150 if (!it.isPresent()) { … … 159 156 160 157 SelectorItem item = it.get(); 161 158 if (this.items.remove(item.getKey(), item)) { 159 clearSelection(); 162 160 savePreferences(); 163 161 filterItems(); 164 162 } … … 168 166 * Opens {@link EditItemDialog} for the selected item, saves the current state 169 167 * to preferences and updates the view. 170 168 */ 171 p rivatesynchronized void editSelectedItem() {169 public synchronized void editSelectedItem() { 172 170 Optional<SelectorItem> it = this.getSelectedItem(); 173 171 174 172 if (!it.isPresent()) { … … 184 182 componentParent, 185 183 tr("Edit item"), 186 184 item, 187 tr("Save") );185 tr("Save"), tr("Cancel")); 188 186 dialog.showDialog(); 189 187 190 188 Optional<SelectorItem> editedItem = dialog.getOutputItem(); … … 201 199 * Opens {@link EditItemDialog}, saves the state to preferences if a new item is added 202 200 * and updates the view. 203 201 */ 204 p rivatesynchronized void createNewItem() {202 public synchronized void createNewItem() { 205 203 EditItemDialog dialog = new EditItemDialog(componentParent, tr("Add snippet"), tr("Add")); 206 204 dialog.showDialog(); 207 205 208 206 Optional<SelectorItem> newItem = dialog.getOutputItem(); 209 207 newItem.ifPresent(i -> { 210 items.put(i.getKey(), new SelectorItem(i.getKey(), i.getQuery()));208 items.put(i.getKey(), i); 211 209 savePreferences(); 212 210 filterItems(); 213 211 }); … … 221 219 @Override 222 220 protected void filterItems() { 223 221 String text = edSearchText.getText().toLowerCase(Locale.ENGLISH); 224 225 super.lsResultModel.setItems(this.items.values().stream()222 List<SelectorItem> matchingItems = this.items.values().stream() 223 .sorted((i1, i2) -> i2.getLastEdit().compareTo(i1.getLastEdit())) 226 224 .filter(item -> item.getKey().contains(text)) 227 .collect(Collectors.toList())); 225 .collect(Collectors.toList()); 226 227 super.lsResultModel.setItems(matchingItems); 228 228 } 229 229 230 230 private void doubleClickEvent() { … … 247 247 Map<String, String> it = new HashMap<>(); 248 248 it.put(KEY_KEY, item.getKey()); 249 249 it.put(QUERY_KEY, item.getQuery()); 250 it.put( USE_COUNT_KEY, Integer.toString(item.getUsageCount()));250 it.put(LAST_EDIT_KEY, item.getLastEdit().format(FORMAT)); 251 251 252 252 toSave.add(it); 253 253 } … … 265 265 Map<String, SelectorItem> result = new HashMap<>(); 266 266 267 267 for (Map<String, String> entry : toRetrieve) { 268 String key = entry.get(KEY_KEY); 269 String query = entry.get(QUERY_KEY); 270 int usageCount = Integer.parseInt(entry.get(USE_COUNT_KEY)); 268 try { 269 String key = entry.get(KEY_KEY); 270 String query = entry.get(QUERY_KEY); 271 LocalDateTime lastEdit = LocalDateTime.parse(entry.get(LAST_EDIT_KEY), FORMAT); 271 272 272 result.put(key, new SelectorItem(key, query, usageCount)); 273 result.put(key, new SelectorItem(key, query, lastEdit)); 274 } catch (IllegalArgumentException | DateTimeParseException e) { 275 // skip any corrupted item 276 Main.error(e); 277 } 273 278 } 274 279 275 280 return result; … … 411 416 412 417 private final JTextField name; 413 418 private final JosmTextArea query; 414 private final int initialNameHash;415 419 416 420 private final transient AbstractTextComponentValidator queryValidator; 417 421 private final transient AbstractTextComponentValidator nameValidator; … … 419 423 private static final int SUCCESS_BTN = 0; 420 424 private static final int CANCEL_BTN = 1; 421 425 426 private final transient SelectorItem itemToEdit; 427 422 428 /** 423 429 * Added/Edited object to be returned. If {@link Optional#empty()} then probably 424 430 * the user closed the dialog, otherwise {@link SelectorItem} is present. … … 436 442 String... buttonTexts) { 437 443 super(parent, title, buttonTexts); 438 444 439 String nameToEdit = itemToEdit != null ? itemToEdit.getKey() : ""; 440 String queryToEdit = itemToEdit != null ? itemToEdit.getQuery() : ""; 441 this.initialNameHash = nameToEdit.hashCode(); 445 this.itemToEdit = itemToEdit; 442 446 447 String nameToEdit = itemToEdit == null ? "" : itemToEdit.getKey(); 448 String queryToEdit = itemToEdit == null ? "" : itemToEdit.getQuery(); 449 443 450 this.name = new JTextField(nameToEdit); 444 451 this.query = new JosmTextArea(queryToEdit); 445 452 … … 457 464 @Override 458 465 public boolean isValid() { 459 466 String currentName = name.getText(); 460 int currentHash = currentName.hashCode();461 467 462 return !Utils.isStripEmpty(currentName) && 463 !(currentHash != initialNameHash && 464 items.containsKey(currentName)); 468 boolean notEmpty = !Utils.isStripEmpty(currentName); 469 boolean exist = !currentName.equals(nameToEdit) && 470 items.containsKey(currentName); 471 472 return notEmpty && !exist; 465 473 } 466 474 }; 467 475 … … 477 485 panel.add(this.name, GBC.eol().insets(5).anchor(GBC.SOUTHEAST).fill(GBC.HORIZONTAL)); 478 486 panel.add(queryScrollPane, constraint); 479 487 480 setDefaultButton(SUCCESS_BTN );481 setCancelButton(CANCEL_BTN );488 setDefaultButton(SUCCESS_BTN + 1); 489 setCancelButton(CANCEL_BTN + 1); 482 490 setPreferredSize(new Dimension(400, 400)); 483 491 setContent(panel, false); 484 492 } … … 500 508 tr("The item cannot be created with provided name"), 501 509 tr("Warning"), 502 510 JOptionPane.WARNING_MESSAGE); 511 512 return; 503 513 } else if (!this.queryValidator.isValid()) { 504 514 JOptionPane.showMessageDialog( 505 515 componentParent, … … 506 516 tr("The item cannot be created with an empty query"), 507 517 tr("Warning"), 508 518 JOptionPane.WARNING_MESSAGE); 509 } else { 510 this.outputItem = Optional.of(new SelectorItem(this.name.getText(), this.query.getText())); 511 super.buttonAction(buttonIndex, evt); 519 520 return; 521 } else if (this.itemToEdit != null) { // editing the item 522 String newKey = this.name.getText(); 523 String newQuery = this.query.getText(); 524 525 String itemKey = this.itemToEdit.getKey(); 526 String itemQuery = this.itemToEdit.getQuery(); 527 528 this.outputItem = Optional.of(new SelectorItem( 529 this.name.getText(), 530 this.query.getText(), 531 !newKey.equals(itemKey) || !newQuery.equals(itemQuery) 532 ? LocalDateTime.now() 533 : this.itemToEdit.getLastEdit())); 534 535 } else { // creating new 536 this.outputItem = Optional.of(new SelectorItem( 537 this.name.getText(), 538 this.query.getText())); 512 539 } 513 } else {514 super.buttonAction(buttonIndex, evt);515 540 } 541 542 super.buttonAction(buttonIndex, evt); 516 543 } 517 544 } 518 545 … … 523 550 public static class SelectorItem { 524 551 private final String itemKey; 525 552 private final String query; 526 private int usageCount;553 private final LocalDateTime lastEdit; 527 554 528 555 /** 529 556 * Constructs a new {@code SelectorItem}. … … 533 560 * @exception IllegalArgumentException if any parameter is empty. 534 561 */ 535 562 public SelectorItem(String key, String query) { 536 this(key, query, 1);563 this(key, query, LocalDateTime.now()); 537 564 } 538 565 539 566 /** … … 540 567 * Constructs a new {@code SelectorItem}. 541 568 * @param key The key of this item. 542 569 * @param query The query of the item. 543 * @param usageCount The number of times this query was used.570 * @param lastEdit The latest when the item was 544 571 * @exception NullPointerException if any parameter is {@code null}. 545 572 * @exception IllegalArgumentException if any parameter is empty. 546 573 */ 547 public SelectorItem(String key, String query, int usageCount) { 548 Objects.requireNonNull(key); 549 Objects.requireNonNull(query); 574 public SelectorItem(String key, String query, LocalDateTime lastEdit) { 575 Objects.requireNonNull(key, "The name of the item cannot be null"); 576 Objects.requireNonNull(query, "The query of the item cannot be null"); 577 Objects.requireNonNull(lastEdit, "The last edit date time cannot be null"); 550 578 551 579 if (Utils.isStripEmpty(key)) { 552 580 throw new IllegalArgumentException("The key of the item cannot be empty"); … … 557 585 558 586 this.itemKey = key; 559 587 this.query = query; 560 this. usageCount = usageCount;588 this.lastEdit = lastEdit; 561 589 } 562 590 563 591 /** … … 577 605 } 578 606 579 607 /** 580 * Gets the number of times the query was used by the user.581 * @return The usage count of this item.608 * Gets the latest date time when the item was created/changed. 609 * @return The latest date time when the item was created/changed. 582 610 */ 583 public int getUsageCount() {584 return this.usageCount;611 public LocalDateTime getLastEdit() { 612 return lastEdit; 585 613 } 586 614 587 /**588 * Increments the {@link SelectorItem#usageCount} by one till589 * it reaches {@link Integer#MAX_VALUE}.590 */591 public void increaseUsageCount() {592 if (this.usageCount < Integer.MAX_VALUE) {593 this.usageCount++;594 }595 }596 597 /**598 * Decrements the {@link SelectorItem#usageCount} ny one till599 * it reaches 0.600 */601 public void decreaseUsageCount() {602 if (this.usageCount > 0) {603 this.usageCount--;604 }605 }606 607 615 @Override 608 616 public int hashCode() { 609 617 final int prime = 31; -
src/org/openstreetmap/josm/gui/download/OverpassQueryWizardDialog.java
36 36 */ 37 37 public final class OverpassQueryWizardDialog extends ExtendedDialog { 38 38 39 private final HistoryComboBox queryWizard; 39 40 private static final String HEADLINE_START = "<h3>"; 40 41 private static final String HEADLINE_END = "</h3>"; 41 42 private static final String TR_START = "<tr>"; … … 42 43 private static final String TR_END = "</tr>"; 43 44 private static final String TD_START = "<td>"; 44 45 private static final String TD_END = "</td>"; 45 private final HistoryComboBox queryWizard;46 private final OverpassTurboQueryWizard overpassQueryBuilder;46 private static final String SPAN_START = "<span>"; 47 private static final String SPAN_END = "</span>"; 47 48 private static final CollectionProperty OVERPASS_WIZARD_HISTORY = 48 49 new CollectionProperty("download.overpass.wizard", new ArrayList<String>()); 50 private final transient OverpassTurboQueryWizard overpassQueryBuilder; 49 51 50 52 // dialog buttons 51 53 private static final int BUILD_QUERY = 0; … … 199 201 .append("<table>").append(TR_START).append(TD_START) 200 202 .append(Utils.joinAsHtmlUnorderedList(Arrays.asList("<i>type:node</i>", "<i>type:relation</i>", "<i>type:way</i>"))) 201 203 .append(TD_END).append(TD_START) 202 .append( "<span>").append(tr("Download objects of a certain type.")).append("</span>")204 .append(SPAN_START).append(tr("Download objects of a certain type.")).append(SPAN_END) 203 205 .append(TD_END).append(TR_END) 204 206 .append(TR_START).append(TD_START) 205 207 .append(Utils.joinAsHtmlUnorderedList( … … 214 216 "is set to 1000m, but it can be changed in the generated query.", "<i>tourism=hotel around Berlin</i> -"), 215 217 tr("{0} all objects within the current selection that have {1} as attribute.", "<i>tourism=hotel in bbox</i> -", 216 218 "'tourism=hotel'")))) 217 .append( "<span>")219 .append(SPAN_START) 218 220 .append(tr("Instead of <i>location</i> any valid place name can be used like address, city, etc.")) 219 .append( "</span>")221 .append(SPAN_END) 220 222 .append(TD_END).append(TR_END) 221 223 .append(TR_START).append(TD_START) 222 224 .append(Utils.joinAsHtmlUnorderedList(Arrays.asList("<i>key=value</i>", "<i>key=*</i>", "<i>key~regex</i>", … … 230 232 tr("<i>expression1 {0} expression2</i>", "or"), 231 233 tr("<i>expression1 {0} expression2</i>", "and")))) 232 234 .append(TD_END).append(TD_START) 233 .append( "<span>")235 .append(SPAN_START) 234 236 .append(tr("Basic logical operators can be used to create more sophisticated queries. Instead of \"or\" - \"|\", \"||\" " + 235 237 "can be used, and instead of \"and\" - \"&\", \"&&\".")) 236 .append( "</span>")238 .append(SPAN_END) 237 239 .append(TD_END).append(TR_END).append("</table>") 238 240 .append("</body>") 239 241 .append("</html>")