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