/******************************************************************************* * Copyright (c) 2012 xored software, Inc. All rights reserved. This program and the accompanying * materials are made available under the terms of the Eclipse Public License v1.0 which accompanies * this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html Contributors: * xored software, Inc. - initial API and implementation (Yuri Strot) ******************************************************************************/ package com.xored.glance.internal.ui.search; import com.xored.glance.internal.ui.GlancePlugin; import com.xored.glance.internal.ui.panels.SearchPanelManager; import com.xored.glance.internal.ui.panels.SearchStatusLine; import com.xored.glance.internal.ui.preferences.IPreferenceConstants; import com.xored.glance.internal.ui.sources.ISourceProviderListener; import com.xored.glance.internal.ui.sources.TextSourceMaker; import com.xored.glance.internal.ui.sources.TextSourceManager; import com.xored.glance.ui.panels.ISearchPanel; import com.xored.glance.ui.panels.ISearchPanelListener; import com.xored.glance.ui.sources.ITextSource; import com.xored.glance.ui.sources.Match; import com.xored.glance.ui.sources.SourceSelection; import com.xored.glance.ui.utils.UITextSource; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.swt.SWTException; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Control; import org.eclipse.ui.IWindowListener; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author Yuri Strot */ public class SearchManager { private class SearchListener implements ISearchListener { private Match firstMatch; @Override public void allFound(final Match[] matches) { if (panel != null) { panel.allFound(matches); } } @Override public void finished() { if (panel != null) { panel.finished(); if (firstMatch != null) { panel.setMatchIndex(firstMatch.getIndex()); firstMatch = null; } } } @Override public void firstFound(final Match match) { if (panel != null) { panel.firstFound(match); firstMatch = match; } } @Override public void setMatchIndex(int index) { if (panel != null) { panel.setMatchIndex(index); } } } private class SearchPanelListener implements ISearchPanelListener { private final ISearchPanel panel; public SearchPanelListener(final ISearchPanel panel) { this.panel = panel; } @Override public void clearStatus() { if (panel != null) { panel.clearStatus(); } } @Override public void close() { dispose(panel); } @Override public void findNext() { if (isCurrent()) { find(rule, SearchManager.FIND_NEXT); } } @Override public void findPrevious() { if (isCurrent()) { find(rule, SearchManager.FIND_PREVIOUS); } } @Override public void indexCanceled() { if (monitor != null) { monitor.setCanceled(true); monitor = null; } } @Override public void ruleChanged(final SearchRule rule) { if (isCurrent()) { find(rule, SearchManager.FIND_HERE); } } @Override public void sourceSelectionChanged() { if (isCurrent()) { engine.updateSourceSelection(); } } protected boolean isCurrent() { return panel.equals(SearchManager.this.panel); } } private class SourceListener implements ISourceProviderListener { @Override public void sourceChanged(final TextSourceMaker source) { update(source, false); } } /** Searching from the current position */ public static final int FIND_HERE = 0; /** Searching next occurrence of the string */ public static final int FIND_NEXT = 1; /** Searching previous occurrence of the string */ public static final int FIND_PREVIOUS = 2; public static SearchManager getIntance() { if (manager == null) { manager = new SearchManager(); } return manager; } private IProgressMonitor monitor; private static SearchManager manager; private final SearchListener searchListener; private SourceListener sourceListener; private final Map<ISearchPanel, SearchPanelListener> panelToListener; private SearchEngine engine; private final List<ISearchPanel> panels; private ISearchPanel panel; private ITextSource source; private TextSourceMaker creator; private int type; private SearchRule rule; private SearchManager() { panels = new ArrayList<ISearchPanel>(); searchListener = new SearchListener(); panelToListener = new HashMap<ISearchPanel, SearchPanelListener>(); } public boolean activate() { final TextSourceMaker source = TextSourceManager.getInstance().getSource(); if (update(source, true)) { forceFocus(); return true; } return false; } public void clearHistory() { if (panel != null) { panel.clearHistory(); } } public void close() { if (panel != null) { panel.closePanel(); } } public void findNext() { if (panel != null) { panel.findNext(); } } public void findPrevious() { if (panel != null) { panel.findPrevious(); } } public ITextSource getSource() { return source; } public void index() { if (panel != null && source != null && !source.isDisposed()) { monitor = new SearchProgressMonitor(panel); new Thread() { @Override public void run() { panel.setIndexingState(ISearchPanel.INDEXING_STATE_IN_PROGRESS); if (source != null) { source.index(monitor); } } }.start(); } } public boolean isInWindow(final IWorkbenchWindow window) { for (final ISearchPanel panel : panels) { if (panel instanceof SearchStatusLine) { final SearchStatusLine sl = ((SearchStatusLine) panel); if (sl.getWindow() == window) { return true; } } } return false; } public void selectAll() { if (panel != null) { panel.selectAll(); } } public void setStatusLine(final IWorkbenchWindow window, final boolean open) { final ISearchPanel panel = SearchStatusLine.getSearchLine(window); if (!open) { panel.closePanel(); return; } panels.add(panel); final SearchPanelListener listener = new SearchPanelListener(panel); panel.addPanelListener(listener); panelToListener.put(panel, listener); updateSourceListener(); final TextSourceMaker source = TextSourceManager.getInstance().getSource(); if (source != null && source.getControl() != null && panel.isApplicable(source.getControl())) { this.panel = panel; rule = panel.getRule(); if (setDescription(source)) { updateEnabling(); } } } public void sourceFocus() { ITextSource source = getSource(); if (source instanceof UITextSource) { UITextSource uiTextSource = (UITextSource) source; if (uiTextSource.getControl() != null) { uiTextSource.getControl().setFocus(); } } } public void startup() { PlatformUI.getWorkbench().addWindowListener(new IWindowListener() { @Override public void windowActivated(final IWorkbenchWindow window) { } @Override public void windowClosed(final IWorkbenchWindow window) { } @Override public void windowDeactivated(final IWorkbenchWindow window) { } @Override public void windowOpened(final IWorkbenchWindow window) { setStatusLine(window, true); } }); for (final IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) { setStatusLine(window, true); } } protected void dispose(final ISearchPanel panel) { panels.remove(panel); final SearchPanelListener listener = panelToListener.remove(panel); panel.removePanelListener(listener); if (panel == this.panel) { this.panel = null; if (source != null) { source.dispose(); source = null; } if (creator != null) { final Control control = creator.getControl(); if (control != null && !control.isDisposed()) { control.forceFocus(); } creator = null; } rule = null; } if (panels.size() == 0) { if (engine != null) { engine.exit(); engine = null; } if (sourceListener != null) { TextSourceManager.getInstance().removeSourceProviderListener(sourceListener); sourceListener = null; } } else { updateSourceListener(); } } protected boolean isParent(final Control parent, Control child) { while (child != null) { if (child.equals(parent)) { return true; } child = child.getParent(); } return false; } protected boolean setDescription(final TextSourceMaker descriptor) { // ignore panel controls if (descriptor != null && panel != null && panel.getControl() != null) { if (isParent(panel.getControl(), descriptor.getControl())) { if (source != null && descriptor.getControl() instanceof Combo) { getSearchEngine().setSource(rule, source, true); source.init(); updateIndexingState(); } return false; } } // ignore the same source if (descriptor == null) { if (this.creator == null) { return false; } } else if (descriptor.equals(this.creator)) { return false; } if (source != null) { try { source.dispose(); } catch (SWTException ex) { // ignore widget is disposed problems } source = null; this.creator = null; } if (descriptor != null && descriptor.isValid()) { this.creator = descriptor; source = new UITextSource(descriptor.create(), descriptor.getControl()); getSearchEngine().setSource(rule, source, true); source.init(); updateIndexingState(); } return true; } protected void updateEnabling() { if (panel != null) { panel.setEnabled(source != null); if (source == null) { panel.setIndexingState(ISearchPanel.INDEXING_STATE_FINISHED); } } } protected void updateSearch(final SearchRule rule, final boolean paused) { getSearchEngine().setRule(rule); } protected void updateSelection() { if (type == FIND_NEXT) { getSearchEngine().selectNext(); } else if (type == FIND_PREVIOUS) { getSearchEngine().selectPrev(); } } private void find(final SearchRule rule, final int type) { this.type = type; if (rule != null) { final boolean textEquals = rule.isTextEquals(this.rule); final boolean settingsEqual = rule.isSettingsEqual(this.rule); if (textEquals) { if (settingsEqual) { updateSelection(); } else { updateSearch(rule, false); } } else { updateSearch(rule, true); } } else { updateSearch(rule, false); } this.rule = rule; } private void forceFocus() { String text = ""; if (source != null) { final SourceSelection selection = source.getSelection(); if (selection != null) { text = selection.getBlock().getText(); final int offset = selection.getOffset(); final int length = selection.getLength(); if (offset + length <= text.length()) { text = text.substring(offset, offset + length); } else { text = ""; } } } panel.setFocus(text); } private SearchEngine getSearchEngine() { if (engine == null) { engine = new SearchEngine(searchListener); engine.start(); } return engine; } private boolean update(final TextSourceMaker source, final boolean openNewPanel) { updatePanel(source, openNewPanel); if (panel != null) { rule = panel.getRule(); updateSourceListener(); if (setDescription(source)) { updateEnabling(); } return true; } return false; } private void updateIndexingState() { if (monitor != null) { monitor.setCanceled(true); monitor = null; } final boolean indexRequired = source != null && !source.isDisposed() && source.isIndexRequired(); if (GlancePlugin.getDefault().getPreferenceStore().getBoolean( IPreferenceConstants.PANEL_AUTO_INDEXING) && indexRequired) { index(); } else { panel.setIndexingState(indexRequired ? ISearchPanel.INDEXING_STATE_INITIAL : ISearchPanel.INDEXING_STATE_DISABLE); } } private void updatePanel(final TextSourceMaker source, final boolean openNewPanel) { final Control control = source.getControl(); if (panel != null) { if (panel.isApplicable(control)) { return; } if (this.source != null) { this.source.dispose(); this.source = null; } creator = null; panel = null; } for (final ISearchPanel panel : panels) { if (panel.isApplicable(control)) { this.panel = panel; break; } } if (panel == null && openNewPanel) { panel = SearchPanelManager.getInstance().getPanel(control); if (panel != null) { panels.add(panel); final SearchPanelListener listener = new SearchPanelListener(panel); panel.addPanelListener(listener); panelToListener.put(panel, listener); } } } private void updateSourceListener() { if (sourceListener == null) { sourceListener = new SourceListener(); TextSourceManager.getInstance().addSourceProviderListener(sourceListener); } } }