1 package org.columba.mail.search; 2 3 import java.net.URI ; 4 import java.text.DateFormat ; 5 import java.text.MessageFormat ; 6 import java.text.SimpleDateFormat ; 7 import java.util.Collections ; 8 import java.util.Comparator ; 9 import java.util.Date ; 10 import java.util.Hashtable ; 11 import java.util.Iterator ; 12 import java.util.List ; 13 import java.util.Locale ; 14 import java.util.Map ; 15 import java.util.ResourceBundle ; 16 import java.util.TimeZone ; 17 import java.util.Vector ; 18 import java.util.logging.Logger ; 19 20 import javax.swing.ImageIcon ; 21 22 import org.columba.api.gui.frame.IFrameMediator; 23 import org.columba.api.plugin.PluginLoadingFailedException; 24 import org.columba.core.command.CommandProcessor; 25 import org.columba.core.filter.FilterCriteria; 26 import org.columba.core.filter.FilterRule; 27 import org.columba.core.gui.frame.FrameManager; 28 import org.columba.core.gui.search.StringCriteriaRenderer; 29 import org.columba.core.gui.search.api.ICriteriaRenderer; 30 import org.columba.core.gui.search.api.IResultPanel; 31 import org.columba.core.resourceloader.ImageLoader; 32 import org.columba.core.search.SearchCriteria; 33 import org.columba.core.search.api.ISearchCriteria; 34 import org.columba.core.search.api.ISearchProvider; 35 import org.columba.core.search.api.ISearchRequest; 36 import org.columba.core.search.api.ISearchResult; 37 import org.columba.mail.command.MailFolderCommandReference; 38 import org.columba.mail.filter.MailFilterFactory; 39 import org.columba.mail.folder.IMailFolder; 40 import org.columba.mail.folder.virtual.VirtualFolder; 41 import org.columba.mail.folder.virtual.VirtualHeader; 42 import org.columba.mail.gui.frame.TreeViewOwner; 43 import org.columba.mail.gui.search.ComplexResultPanel; 44 import org.columba.mail.gui.search.CriteriaResultPanel; 45 import org.columba.mail.gui.table.command.ViewHeaderListCommand; 46 import org.columba.mail.gui.tree.FolderTreeModel; 47 import org.columba.mail.message.IHeaderList; 48 import org.columba.mail.resourceloader.IconKeys; 49 import org.columba.mail.resourceloader.MailImageLoader; 50 import org.columba.ristretto.message.Address; 51 import org.columba.ristretto.message.Flags; 52 53 58 public class MailSearchProvider implements ISearchProvider { 59 private static final String CRITERIA_BODY_CONTAINS = "body_contains"; 60 61 public static final String CRITERIA_FROM_CONTAINS = "from_contains"; 62 63 private static final String CRITERIA_SIZE_GREATER_THAN = "size_greater_than"; 64 65 private static final String CRITERIA_SIZE_SMALLER_THAN = "size_smaller_than"; 66 67 private static final String CRITERIA_SUBJECT_CONTAINS = "subject_contains"; 68 69 private static final Logger LOG = Logger 70 .getLogger("org.columba.mail.search.MailSearchProvider"); 71 72 private Vector <SearchIndex> indizes = new Vector <SearchIndex>(); 73 74 private Map <String , VirtualFolder> searchFolders = new Hashtable <String , VirtualFolder>(); 75 private VirtualFolder lastSearchFolder; 76 77 private int totalResultCount = 0; 78 79 private ResourceBundle bundle; 80 81 84 private boolean singleCriteriaSearch = false; 85 86 public MailSearchProvider() { 87 bundle = ResourceBundle.getBundle("org.columba.mail.i18n.search"); 88 89 } 90 91 public String getTechnicalName() { 92 return "MailSearchProvider"; 93 } 94 95 public String getName() { 96 return bundle.getString("provider_title"); 97 } 98 99 public String getDescription() { 100 return bundle.getString("provider_description"); 101 } 102 103 public ImageIcon getIcon() { 104 return MailImageLoader.getSmallIcon(IconKeys.MESSAGE_READ); 105 } 106 107 public List <ISearchCriteria> getAllCriteria(String searchTerm) { 108 List <ISearchCriteria> list = new Vector <ISearchCriteria>(); 109 110 boolean numberFormat = false; 112 try { 113 int searchTermInt = Integer.parseInt(searchTerm); 114 numberFormat = true; 115 } catch (NumberFormatException e) { 116 } 117 118 if (searchTerm.equals("")) 119 numberFormat = true; 120 121 122 list.add(getCriteria(MailSearchProvider.CRITERIA_SUBJECT_CONTAINS, 123 searchTerm)); 124 list.add(getCriteria(MailSearchProvider.CRITERIA_FROM_CONTAINS, 125 searchTerm)); 126 list.add(getCriteria(MailSearchProvider.CRITERIA_BODY_CONTAINS, 127 searchTerm)); 128 129 if (numberFormat) 130 list.add(getCriteria(MailSearchProvider.CRITERIA_SIZE_GREATER_THAN, 131 searchTerm)); 132 if (numberFormat) 133 list.add(getCriteria(MailSearchProvider.CRITERIA_SIZE_SMALLER_THAN, 134 searchTerm)); 135 136 return list; 137 } 138 139 public IResultPanel getResultPanel(String searchCriteriaTechnicalName) { 140 return new CriteriaResultPanel(getTechnicalName(), 141 searchCriteriaTechnicalName); 142 } 143 144 public IResultPanel getComplexResultPanel() { 145 return new ComplexResultPanel(getTechnicalName()); 146 } 147 148 public ICriteriaRenderer getCriteriaRenderer( 149 String searchCriteriaTechnicalName) { 150 if (searchCriteriaTechnicalName 151 .equals(MailSearchProvider.CRITERIA_BODY_CONTAINS)) 152 return new StringCriteriaRenderer(getCriteria( 153 MailSearchProvider.CRITERIA_BODY_CONTAINS, ""), this); 154 else if (searchCriteriaTechnicalName 155 .equals(MailSearchProvider.CRITERIA_SUBJECT_CONTAINS)) 156 return new StringCriteriaRenderer(getCriteria( 157 MailSearchProvider.CRITERIA_SUBJECT_CONTAINS, ""), this); 158 else if (searchCriteriaTechnicalName 159 .equals(MailSearchProvider.CRITERIA_FROM_CONTAINS)) 160 return new StringCriteriaRenderer(getCriteria( 161 MailSearchProvider.CRITERIA_FROM_CONTAINS, ""), this); 162 else if (searchCriteriaTechnicalName 163 .equals(MailSearchProvider.CRITERIA_SIZE_GREATER_THAN)) 164 return new StringCriteriaRenderer(getCriteria( 165 MailSearchProvider.CRITERIA_SIZE_GREATER_THAN, ""), this); 166 else if (searchCriteriaTechnicalName 167 .equals(MailSearchProvider.CRITERIA_SIZE_SMALLER_THAN)) 168 return new StringCriteriaRenderer(getCriteria( 169 MailSearchProvider.CRITERIA_SIZE_SMALLER_THAN, ""), this); 170 171 else 172 throw new IllegalArgumentException ("no renderer available for <" 173 + searchCriteriaTechnicalName + ">"); 174 } 175 176 public ISearchCriteria getCriteria(String technicalName, String searchTerm) { 177 178 String title = MessageFormat.format(bundle.getString(technicalName 179 + "_title"), new Object [] { searchTerm }); 180 String name = bundle.getString(technicalName + "_name"); 181 String description = MessageFormat.format(bundle 182 .getString(technicalName + "_description"), 183 new Object [] { searchTerm }); 184 185 return new SearchCriteria(technicalName, name, title, description); 186 } 187 188 public List <ISearchResult> query(String searchTerm, 189 String searchCriteriaTechnicalName, boolean searchInside, 190 int startIndex, int resultCount) { 191 192 LOG.info("searchTerm=" + searchTerm); 193 LOG.info("criteriaName=" + searchCriteriaTechnicalName); 194 LOG.info("searchInside=" + searchInside); 195 196 List <ISearchResult> result = new Vector <ISearchResult>(); 197 198 indizes = new Vector <SearchIndex>(); 199 200 202 FilterCriteria criteria = createFilterCriteria(searchTerm, 203 searchCriteriaTechnicalName); 204 205 String searchRequestId = searchCriteriaTechnicalName; 207 208 if (!searchInside) { 210 lastSearchFolder = null; 211 } 213 214 if (criteria == null) 217 return result; 218 try { 219 220 227 VirtualFolder folder = null; 228 229 if (searchInside) { 231 if (lastSearchFolder != null) { 232 LOG.info("reuse existing virtual folder"); 233 234 VirtualFolder vFolder = lastSearchFolder; 236 folder = SearchFolderFactory.prepareSearchFolder(criteria, 238 vFolder); 239 } else { 240 totalResultCount = 0; 241 return result; 242 } 243 } else { 244 LOG.info("create new virtual folder"); 245 IMailFolder rootFolder = (IMailFolder) FolderTreeModel 246 .getInstance().getRoot(); 247 folder = SearchFolderFactory.createSearchFolder(criteria, 248 rootFolder); 249 } 250 251 IHeaderList headerList = folder.getHeaderList(); 253 254 Object [] uids = headerList.getUids(); 255 LOG.info("result count=" + uids.length); 256 257 for (int i = 0; i < uids.length; i++) { 258 SearchIndex idx = new SearchIndex(folder, uids[i]); 259 260 263 indizes.add(idx); 264 } 265 266 List <ISearchResult> l = retrieveResultData(indizes, startIndex, 268 resultCount); 269 result.addAll(l); 270 271 Collections.sort(result, new MyComparator()); 273 274 searchFolders.put(searchRequestId, folder); 276 lastSearchFolder = folder; 277 278 LOG.info("cache search folder=" + searchRequestId); 279 280 } catch (Exception e) { 281 throw new RuntimeException (e); 282 } 283 284 totalResultCount = indizes.size(); 286 287 singleCriteriaSearch = true; 288 289 return result; 290 } 291 292 private FilterCriteria createFilterCriteria(String searchTerm, 293 String searchCriteriaTechnicalName) { 294 FilterCriteria criteria = null; 295 if (searchCriteriaTechnicalName 296 .equals(MailSearchProvider.CRITERIA_BODY_CONTAINS)) { 297 criteria = MailFilterFactory.createBodyContains(searchTerm); 298 } else if (searchCriteriaTechnicalName 299 .equals(MailSearchProvider.CRITERIA_SUBJECT_CONTAINS)) { 300 criteria = MailFilterFactory.createSubjectContains(searchTerm); 301 } else if (searchCriteriaTechnicalName 302 .equals(MailSearchProvider.CRITERIA_FROM_CONTAINS)) { 303 criteria = MailFilterFactory.createFromContains(searchTerm); 304 } else if (searchCriteriaTechnicalName 305 .equals(MailSearchProvider.CRITERIA_SIZE_GREATER_THAN)) { 306 criteria = MailFilterFactory.createSizeIsBigger(Integer 307 .parseInt(searchTerm)); 308 } else if (searchCriteriaTechnicalName 309 .equals(MailSearchProvider.CRITERIA_SIZE_SMALLER_THAN)) { 310 criteria = MailFilterFactory.createSizeIsSmaller(Integer 311 .parseInt(searchTerm)); 312 } else 313 throw new IllegalArgumentException ("no criteria <" 314 + searchCriteriaTechnicalName + "> found"); 315 return criteria; 316 } 317 318 public List <ISearchResult> query(List <ISearchRequest> list, 319 boolean matchAll, boolean searchInside, int startIndex, 320 int resultCount) { 321 List <ISearchResult> result = new Vector <ISearchResult>(); 322 323 indizes = new Vector <SearchIndex>(); 324 325 if (!searchInside) { 327 lastSearchFolder = null; 328 } 329 330 FilterRule rule = new FilterRule(); 332 if (matchAll) 333 rule.setCondition(FilterRule.MATCH_ALL); 334 else 335 rule.setCondition(FilterRule.MATCH_ANY); 336 337 Iterator <ISearchRequest> it = list.iterator(); 338 StringBuffer buf = new StringBuffer (); 339 while (it.hasNext()) { 340 ISearchRequest r = it.next(); 341 String searchCriteriaTechnicalName = r.getCriteria(); 342 buf.append(searchCriteriaTechnicalName); 343 344 String searchTerm = r.getSearchTerm(); 345 346 FilterCriteria criteria = createFilterCriteria(searchTerm, 347 searchCriteriaTechnicalName); 348 rule.add(criteria); 349 } 350 351 String searchRequestId = buf.toString(); 353 354 try { 355 356 VirtualFolder folder = null; 357 IMailFolder rootFolder = (IMailFolder) FolderTreeModel 359 .getInstance().getRoot(); 360 361 if (searchInside && (lastSearchFolder != null) ) { 362 folder = lastSearchFolder; 363 364 SearchFolderFactory.prepareSearchFolder(rule, folder); 365 } else { 366 folder = SearchFolderFactory.createSearchFolder(rule, 367 rootFolder); 368 } 369 370 IHeaderList headerList = folder.getHeaderList(); 372 373 Object [] uids = headerList.getUids(); 374 375 for (int i = 0; i < uids.length; i++) { 376 SearchIndex idx = new SearchIndex(folder, uids[i]); 377 380 indizes.add(idx); 381 } 382 383 List <ISearchResult> l = retrieveResultData(indizes, startIndex, 385 resultCount); 386 result.addAll(l); 387 388 Collections.sort(result, new MyComparator()); 390 391 searchFolders.put(searchRequestId, folder); 393 lastSearchFolder = folder; 394 395 } catch (Exception e) { 396 throw new RuntimeException (e); 397 } 398 399 totalResultCount = indizes.size(); 401 402 singleCriteriaSearch = false; 403 404 return result; 405 } 406 407 private List <ISearchResult> retrieveResultData(Vector <SearchIndex> indizes, 408 int startIndex, int resultCount) throws Exception { 409 int count = (startIndex + resultCount <= indizes.size()) ? resultCount 411 : indizes.size(); 412 List <ISearchResult> result = new Vector <ISearchResult>(); 413 for (int i = startIndex; i < count; i++) { 415 SearchIndex idx = indizes.get(i); 416 VirtualFolder folder = idx.folder; 417 Object messageId = idx.messageId; 418 419 423 String title = (String ) folder.getAttribute(messageId, 424 "columba.subject"); 425 Address from = (Address) folder.getAttribute(messageId, 426 "columba.from"); 427 Date date = (Date ) folder.getAttribute(messageId, "columba.date"); 428 String description = from.toString() + " " + date; 429 430 VirtualHeader h = (VirtualHeader) folder.getHeaderList().get(messageId); 431 URI uri = SearchResultBuilder.createURI(h.getSrcFolder().getId(), h.getSrcUid()); 432 System.out.println("uri="+uri.toString()); 433 ImageIcon statusIcon = null; 434 Flags flags = folder.getFlags(messageId); 435 if (flags.getDeleted()) { 436 statusIcon = ImageLoader.getSmallIcon("user-trash.png"); 437 438 } else if (flags.getAnswered()) { 439 statusIcon = MailImageLoader 440 .getSmallIcon("message-mail-replied.png"); 441 } else if (flags.getDraft()) { 442 statusIcon = MailImageLoader.getSmallIcon("edit.png"); 443 } else if (!flags.getSeen()) { 444 statusIcon = MailImageLoader 445 .getSmallIcon("message-mail-unread.png"); 446 } else if (flags.getSeen()) { 447 statusIcon = MailImageLoader 448 .getSmallIcon("message-mail-read.png"); 449 } 450 451 String dateString = new DateHelper().format(date); 452 453 result.add(new MailSearchResult(title, description, uri, 454 dateString, date, from, statusIcon, flags.getFlagged())); 455 } 456 return result; 457 } 458 459 class DateHelper { 460 SimpleDateFormat dfWeek = new SimpleDateFormat ("EEE HH:mm", Locale 461 .getDefault()); 462 463 DateFormat dfCommon = DateFormat.getDateInstance(); 465 466 static final long OneDay = 24 * 60 * 60 * 1000; 467 468 TimeZone localTimeZone = TimeZone.getDefault(); 469 470 private int getLocalDaysDiff(long t) { 471 return (int) (((System.currentTimeMillis() + localTimeZone 472 .getRawOffset()) - (((t + localTimeZone.getRawOffset()) / OneDay) * OneDay)) / OneDay); 473 } 474 475 public String format(Date date) { 476 String dateString = null; 477 478 int diff = getLocalDaysDiff(date.getTime()); 479 480 if ((diff >= 0) && (diff < 7)) { 482 dateString = dfWeek.format(date); 483 } else { 484 dateString = dfCommon.format(date); 485 } 486 return dateString; 487 } 488 489 } 490 491 class SearchIndex { 492 VirtualFolder folder; 493 494 Object messageId; 495 496 SearchIndex(VirtualFolder folder, Object messageId) { 497 this.folder = folder; 498 this.messageId = messageId; 499 } 500 } 501 502 public int getTotalResultCount() { 503 return totalResultCount; 504 } 505 506 public void showAllResults(IFrameMediator mediator, String searchTerm, 507 String searchCriteriaTechnicalName) { 508 509 VirtualFolder vFolder = lastSearchFolder; 510 if (searchCriteriaTechnicalName == null) { 512 vFolder = searchFolders.values().iterator().next(); 513 } else 514 vFolder = searchFolders.get(searchCriteriaTechnicalName); 515 516 if (vFolder == null) 517 throw new IllegalArgumentException ("vFolder for search critera <" 518 + searchCriteriaTechnicalName + "> not found"); 519 520 IFrameMediator newMediator = null; 522 try { 523 newMediator = FrameManager.getInstance().switchView( 524 mediator.getContainer(), "ThreePaneMail"); 525 } catch (PluginLoadingFailedException e) { 526 e.printStackTrace(); 527 } 528 529 ((TreeViewOwner) newMediator).getTreeController().setSelected(vFolder); 531 532 CommandProcessor.getInstance().addOp( 534 new ViewHeaderListCommand(newMediator, 535 new MailFolderCommandReference(vFolder))); 536 } 537 538 544 class MyComparator implements Comparator { 545 MyComparator() { 546 } 547 548 public int compare(Object o1, Object o2) { 549 MailSearchResult result = (MailSearchResult) o1; 550 MailSearchResult result2 = (MailSearchResult) o2; 551 552 Date date = result.getDate(); 553 Date date2 = result2.getDate(); 554 555 if (date == null && date2 == null) 556 return 0; 557 if (date != null && date2 == null) 558 return -1; 559 if (date == null && date2 != null) 560 return 1; 561 562 return -date.compareTo(date2); 563 } 564 565 } 566 567 public ISearchCriteria getDefaultCriteria(String searchTerm) { 568 return getCriteria(MailSearchProvider.CRITERIA_SUBJECT_CONTAINS, searchTerm); 569 } 570 571 public boolean hasSingleCriteriaSearchResult() { 572 return singleCriteriaSearch && lastSearchFolder != null; 573 } 574 575 } 576 | Popular Tags |