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