package com.vistatec.ocelot.findrep; import java.awt.Window; import java.util.ArrayList; import java.util.List; import java.util.Locale; import javax.swing.JOptionPane; import com.google.common.eventbus.Subscribe; import com.vistatec.ocelot.events.HighlightEvent; import com.vistatec.ocelot.events.OpenFileEvent; import com.vistatec.ocelot.events.ReplaceDoneEvent; import com.vistatec.ocelot.events.ReplaceEvent; import com.vistatec.ocelot.events.api.OcelotEventQueue; import com.vistatec.ocelot.events.api.OcelotEventQueueListener; import com.vistatec.ocelot.segment.model.OcelotSegment; /** * Controller class supervising all the processes pertaining the Find and * Replace functionality. */ public class FindAndReplaceController implements OcelotEventQueueListener { /** Result found constant. */ public static final int RESULT_FOUND = 0; /** Result not found constant. */ public static final int RESULT_NOT_FOUND = 1; /** Result end of document reached constant. */ public static final int RESULT_END_OF_DOC_REACHED = 2; /** The Ocelot event queue. */ private OcelotEventQueue eventQueue; /** The word finder object. */ private WordFinder wordFinder; /** The find and replace dialog. */ private FindReplaceDialog frDialog; /** The source locale in the opened XLIFF document. */ private Locale sourceLocale; /** The target locale in the opened XLIFF document. */ private Locale targetLocale; /** The list of Ocelot segments. */ private List<OcelotSegment> segments; /** Last searched text. */ private String lastSearchedText; /** List of replaced results. */ private List<Integer> replacedResIdxList; /** * Constructor. * * @param eventQueue * the event queue */ public FindAndReplaceController(OcelotEventQueue eventQueue) { this.eventQueue = eventQueue; wordFinder = new WordFinder(); replacedResIdxList = new ArrayList<Integer>(); } /** * Handles the event a new XLIFF file is opened. * * @param e * the open file event. */ @Subscribe public void fileOpened(OpenFileEvent e) { segments = e.getDocument().getSegments(); sourceLocale = new Locale(e.getDocument().getSrcLocale() .getOriginalLocId()); targetLocale = new Locale(e.getDocument().getTgtLocale() .getOriginalLocId()); if (frDialog != null) { int selectedScope = frDialog.getSelectedScope(); if (selectedScope == WordFinder.SCOPE_SOURCE) { setSourceScope(); } else { setTargetScope(); } } clear(); } /** * Clears the controller. */ private void clear() { lastSearchedText = null; replacedResIdxList.clear(); } /** * Finds the next occurrence of the text. * * @param text * the text to be searched. */ public void findNext(String text) { if (checkDocumentOpened()) { // if the text to be searched has changed, then start to search from // the beginning (or the end) of the document if (lastSearchedText == null || !text.equals(lastSearchedText)) { lastSearchedText = text; replacedResIdxList.clear(); wordFinder.goToStartOfDocument(); wordFinder.clearAllResults(); List<FindResult> results = wordFinder.findWord(text, segments); if (results != null && !results.isEmpty()) { frDialog.displayOccurrenceNum(results.size()); sendHighlightEvent(results); } else { frDialog.setResult(RESULT_NOT_FOUND); eventQueue.post(new HighlightEvent(null, -1)); } // if a list of results already exists, then go to the next // result } else if (wordFinder.getAllResults() != null && !wordFinder.getAllResults().isEmpty()) { do { wordFinder.goToNextResult(); } while (replacedResIdxList.contains(wordFinder .getCurrentResIndex())); if (wordFinder.getCurrentResIndex() != -1 && wordFinder.getCurrentResIndex() != wordFinder .getAllResults().size()) { sendHighlightEvent(wordFinder.getAllResults()); frDialog.setResult(RESULT_FOUND); } else { frDialog.setResult(RESULT_END_OF_DOC_REACHED); } } } } /** * Sends the highlight event for current results. * * @param results * the find results. */ private void sendHighlightEvent(List<FindResult> results) { List<FindResult> resultsToSend = null; int currResIdx = -1; if (replacedResIdxList.isEmpty()) { resultsToSend = results; currResIdx = wordFinder.getCurrentResIndex(); } else { resultsToSend = new ArrayList<FindResult>(); for (int i = 0; i < results.size(); i++) { if (!replacedResIdxList.contains(i)) { resultsToSend.add(results.get(i)); } } currResIdx = resultsToSend.indexOf(results.get(wordFinder .getCurrentResIndex())); } eventQueue.post(new HighlightEvent(resultsToSend, currResIdx)); } /** * Replaces the string currently highlighted in the grid, with a new string. * This method simply sends an event and then the segment view will take * care of the text replacing. * * @param newString * the new string. */ public void replace(String newString) { boolean replace = true; if (newString.isEmpty()) { int option = JOptionPane .showConfirmDialog( frDialog, "Do you want to replace the selected occurrence with an empty string?", "Replace", JOptionPane.YES_NO_OPTION); replace = option == JOptionPane.YES_OPTION; } if (replace) { frDialog.hideOccNumber(); if (replacedResIdxList.contains(wordFinder.getCurrentResIndex())) { findNext(lastSearchedText); } else if (wordFinder.getCurrentResIndex() != -1) { eventQueue.post(new ReplaceEvent(newString, wordFinder.getAllResults() .get(wordFinder.getCurrentResIndex()) .getSegmentIndex(), ReplaceEvent.REPLACE)); wordFinder.replacedString(newString); replacedResIdxList.add(wordFinder.getCurrentResIndex()); if (replacedResIdxList.size() == wordFinder .getAllResults().size()) { wordFinder.clearAllResults(); clear(); } } } } /** * Set the scope to the source. */ public void setSourceScope() { wordFinder.setScope(WordFinder.SCOPE_SOURCE, sourceLocale); clear(); } /** * Sets the scope to the target. */ public void setTargetScope() { wordFinder.setScope(WordFinder.SCOPE_TARGET, targetLocale); clear(); } /** * Sets the "whole word" option. * * @param wholeWord * if <true> the whole word option will be set. */ public void setWholeWord(boolean wholeWord) { wordFinder.enableOption(WordFinder.WHOLE_WORD_OPTION, wholeWord); clear(); } /** * Sets the "case sensitive" option. * * @param caseSensitive * if <true> the case sensitive option will be set. */ public void setCaseSensitive(boolean caseSensitive) { wordFinder .enableOption(WordFinder.CASE_SENSITIVE_OPTION, caseSensitive); clear(); } /** * Sets the search direction to "down". */ public void setSearchDirectionDown() { wordFinder.setDirection(WordFinder.DIRECTION_DOWN); } /** * Sets the search direction to "up". */ public void setSearchDirectionUp() { wordFinder.setDirection(WordFinder.DIRECTION_UP); } /** * Displays the find and replace dialog. * * @param owner * the owner window. */ public void displayDialog(Window owner) { if (frDialog == null) { frDialog = new FindReplaceDialog(owner, this); frDialog.open(); } else { frDialog.requestFocus(); } } /** * Closes the find and replace dialog. */ public void closeDialog() { wordFinder.reset(); frDialog = null; clear(); } /** * Checks if there is a XLIFF document currently opened in Ocelot. * * @return <code>true</code> if a document is opened; <code>false</code> * otherwise. */ private boolean checkDocumentOpened() { return sourceLocale != null && targetLocale != null && segments != null; } /** * Enable/Disable the wrap search option. * * @param enable * if <code>true</code> the wrap search is set. */ public void setWrapSearch(boolean enable) { wordFinder.enableOption(WordFinder.WRAP_SEARCH_OPTION, enable); } /** * Replaces all the highlighted strings with a specific text. * * @param text * the text */ public void replaceAll(String text) { boolean replace = true; if (text.isEmpty()) { int option = JOptionPane .showConfirmDialog( frDialog, "Do you want to replace all occurrences with an empty string?", "Replace", JOptionPane.YES_NO_OPTION); replace = option == JOptionPane.YES_OPTION; } if (replace) { eventQueue.post(new ReplaceEvent(text, ReplaceEvent.REPLACE_ALL)); wordFinder.clearAllResults(); clear(); } } /** * Once all occurrences have been replaced, it prompt a message to the user * displaying the number of replaced occurrences. * * @param e * the replace done event. */ @Subscribe public void handleReplaceAllDone(ReplaceDoneEvent e) { if (frDialog != null) { JOptionPane.showMessageDialog(frDialog, "Replaced " + e.getReplacedOccurrencesNum() + " occurrences.", "Replace All", JOptionPane.INFORMATION_MESSAGE); } } }