001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.osm.search; 003 004import static org.openstreetmap.josm.tools.I18n.trc; 005 006import java.util.Objects; 007 008import org.openstreetmap.josm.tools.Logging; 009 010/** 011 * This class defines a set of parameters that is used to 012 * perform search within the search dialog. 013 * @since 12659 (extracted from {@code SearchAction}) 014 */ 015public class SearchSetting { 016 /** Search text */ 017 public String text; 018 /** Search mode */ 019 public SearchMode mode; 020 /** {@code true} to perform a case-sensitive search */ 021 public boolean caseSensitive; 022 /** {@code true} to perform a regex-based search */ 023 public boolean regexSearch; 024 /** {@code true} to execute a MapCSS selector */ 025 public boolean mapCSSSearch; 026 /** {@code true} to include all objects (even incomplete and deleted ones) */ 027 public boolean allElements; 028 029 /** 030 * Constructs a new {@code SearchSetting}. 031 */ 032 public SearchSetting() { 033 text = ""; 034 mode = SearchMode.replace; 035 } 036 037 /** 038 * Constructs a new {@code SearchSetting} from an existing one. 039 * @param original original search settings 040 */ 041 public SearchSetting(SearchSetting original) { 042 text = original.text; 043 mode = original.mode; 044 caseSensitive = original.caseSensitive; 045 regexSearch = original.regexSearch; 046 mapCSSSearch = original.mapCSSSearch; 047 allElements = original.allElements; 048 } 049 050 @Override 051 public String toString() { 052 String cs = caseSensitive ? 053 /*case sensitive*/ trc("search", "CS") : 054 /*case insensitive*/ trc("search", "CI"); 055 String rx = regexSearch ? ", " + 056 /*regex search*/ trc("search", "RX") : ""; 057 String css = mapCSSSearch ? ", " + 058 /*MapCSS search*/ trc("search", "CSS") : ""; 059 String all = allElements ? ", " + 060 /*all elements*/ trc("search", "A") : ""; 061 return '"' + text + "\" (" + cs + rx + css + all + ", " + mode + ')'; 062 } 063 064 @Override 065 public boolean equals(Object other) { 066 if (this == other) return true; 067 if (other == null || getClass() != other.getClass()) return false; 068 SearchSetting that = (SearchSetting) other; 069 return caseSensitive == that.caseSensitive && 070 regexSearch == that.regexSearch && 071 mapCSSSearch == that.mapCSSSearch && 072 allElements == that.allElements && 073 mode == that.mode && 074 Objects.equals(text, that.text); 075 } 076 077 @Override 078 public int hashCode() { 079 return Objects.hash(text, mode, caseSensitive, regexSearch, mapCSSSearch, allElements); 080 } 081 082 /** 083 * <p>Transforms a string following a certain format, namely "[R | A | D | S][C?,R?,A?,M?] [a-zA-Z]" 084 * where the first part defines the mode of the search, see {@link SearchMode}, the second defines 085 * a set of attributes within the {@code SearchSetting} class and the second is the search query. 086 * <p> 087 * Attributes are as follows: 088 * <ul> 089 * <li>C - if search is case sensitive 090 * <li>R - if the regex syntax is used 091 * <li>A - if all objects are considered 092 * <li>M - if the mapCSS syntax is used 093 * </ul> 094 * <p>For example, "RC type:node" is a valid string representation of an object that replaces the 095 * current selection, is case sensitive and searches for all objects of type node. 096 * @param s A string representation of a {@code SearchSetting} object 097 * from which the object must be built. 098 * @return A {@code SearchSetting} defined by the input string. 099 */ 100 public static SearchSetting readFromString(String s) { 101 if (s.isEmpty()) 102 return null; 103 104 SearchSetting result = new SearchSetting(); 105 106 int index = 1; 107 108 result.mode = SearchMode.fromCode(s.charAt(0)); 109 if (result.mode == null) { 110 result.mode = SearchMode.replace; 111 index = 0; 112 } 113 114 while (index < s.length()) { 115 if (s.charAt(index) == 'C') { 116 result.caseSensitive = true; 117 } else if (s.charAt(index) == 'R') { 118 result.regexSearch = true; 119 } else if (s.charAt(index) == 'A') { 120 result.allElements = true; 121 } else if (s.charAt(index) == 'M') { 122 result.mapCSSSearch = true; 123 } else if (s.charAt(index) == ' ') { 124 break; 125 } else { 126 Logging.warn("Unknown char in SearchSettings: " + s); 127 break; 128 } 129 index++; 130 } 131 132 if (index < s.length() && s.charAt(index) == ' ') { 133 index++; 134 } 135 136 result.text = s.substring(index); 137 138 return result; 139 } 140 141 /** 142 * Builds a string representation of the {@code SearchSetting} object, 143 * see {@link #readFromString(String)} for more details. 144 * @return A string representation of the {@code SearchSetting} object. 145 */ 146 public String writeToString() { 147 if (text == null || text.isEmpty()) 148 return ""; 149 150 StringBuilder result = new StringBuilder(); 151 result.append(mode.getCode()); 152 if (caseSensitive) { 153 result.append('C'); 154 } 155 if (regexSearch) { 156 result.append('R'); 157 } 158 if (mapCSSSearch) { 159 result.append('M'); 160 } 161 if (allElements) { 162 result.append('A'); 163 } 164 result.append(' ') 165 .append(text); 166 return result.toString(); 167 } 168}