/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.search2.internal.ui; import com.google.dart.tools.search.internal.ui.ISearchHelpContextIds; import com.google.dart.tools.search.internal.ui.SearchPlugin; import com.google.dart.tools.search.ui.IContextMenuConstants; import com.google.dart.tools.search.ui.IQueryListener; import com.google.dart.tools.search.ui.ISearchQuery; import com.google.dart.tools.search.ui.ISearchResult; import com.google.dart.tools.search.ui.ISearchResultPage; import com.google.dart.tools.search.ui.ISearchResultViewPart; import com.google.dart.tools.search.ui.NewSearchUI; import com.ibm.icu.text.MessageFormat; import org.eclipse.core.commands.operations.IUndoContext; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.action.GroupMarker; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.LegacyActionTools; import org.eclipse.jface.action.Separator; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Link; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IMemento; import org.eclipse.ui.IPropertyListener; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchCommandConstants; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartSite; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.ActionFactory; import org.eclipse.ui.operations.UndoRedoActionGroup; import org.eclipse.ui.part.IPage; import org.eclipse.ui.part.IPageBookViewPage; import org.eclipse.ui.part.IPageSite; import org.eclipse.ui.part.Page; import org.eclipse.ui.part.PageBook; import org.eclipse.ui.part.PageBookView; import org.eclipse.ui.part.PageSwitcher; import org.eclipse.ui.progress.IWorkbenchSiteProgressService; import java.util.HashMap; import java.util.Iterator; import java.util.Map.Entry; public class SearchView extends PageBookView implements ISearchResultViewPart, IQueryListener { static class DummyPart implements IWorkbenchPart { private int fLastActivation = 0; @Override public void addPropertyListener(IPropertyListener listener) {/* dummy */ } @Override public void createPartControl(Composite parent) {/* dummy */ } @Override public void dispose() {/* dummy */ } @Override public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { return null; } public int getLastActivation() { return fLastActivation; } @Override public IWorkbenchPartSite getSite() { return null; } @Override public String getTitle() { return null; } @Override public Image getTitleImage() { return null; } @Override public String getTitleToolTip() { return null; } @Override public void removePropertyListener(IPropertyListener listener) {/* dummy */ } @Override public void setFocus() {/* dummy */ } public void setLastActivation(int lastActivation) { fLastActivation = lastActivation; } } static class EmptySearchView extends Page implements ISearchResultPage { private Composite fControl; private String fId; @Override public void createControl(Composite parent) { Color background = parent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND); Composite composite = new Composite(parent, SWT.NONE); composite.setLayout(new GridLayout(1, false)); composite.setBackground(background); Link link = new Link(composite, SWT.NONE); link.setText(SearchMessages.SearchView_empty_search_label); link.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, true, false)); link.setBackground(background); fControl = composite; } @Override public Control getControl() { return fControl; } @Override public String getID() { return fId; } @Override public String getLabel() { return ""; //$NON-NLS-1$ } @Override public Object getUIState() { // empty implementation return null; } @Override public void init(IPageSite pageSite) { super.init(pageSite); getSite().setSelectionProvider(null); } @Override public void restoreState(IMemento memento) { // do nothing } @Override public void saveState(IMemento memento) { // do nothing } @Override public void setFocus() { if (fControl != null) { fControl.setFocus(); } } @Override public void setID(String id) { fId = id; } @Override public void setInput(ISearchResult search, Object viewState) { // do nothing } @Override public void setViewPart(ISearchResultViewPart part) { // do nothing } } private static final String MEMENTO_TYPE = "view"; //$NON-NLS-1$ private static final String MEMENTO_KEY_LAST_ACTIVATION = "com.google.dart.tools.search.lastActivation"; //$NON-NLS-1$ private static final String MEMENTO_KEY_RESTORE = "com.google.dart.tools.search.restore"; //$NON-NLS-1$ /** * Creates the groups and separators for the search view's context menu * * @param menu the context menu */ public static void createContextMenuGroups(IMenuManager menu) { menu.add(new Separator(IContextMenuConstants.GROUP_NEW)); menu.add(new GroupMarker(IContextMenuConstants.GROUP_SHOW)); menu.add(new GroupMarker(IContextMenuConstants.GROUP_OPEN)); menu.add(new GroupMarker(IContextMenuConstants.GROUP_REMOVE_MATCHES)); menu.add(new Separator(IContextMenuConstants.GROUP_EDIT)); menu.add(new Separator(IContextMenuConstants.GROUP_REORGANIZE)); menu.add(new GroupMarker(IContextMenuConstants.GROUP_GENERATE)); menu.add(new Separator(IContextMenuConstants.GROUP_SEARCH)); menu.add(new Separator(IContextMenuConstants.GROUP_BUILD)); menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); menu.add(new Separator(IContextMenuConstants.GROUP_VIEWER_SETUP)); menu.add(new Separator(IContextMenuConstants.GROUP_PROPERTIES)); } /** * Creates the groups and separators for the search view's tool bar * * @param toolbar the toolbar */ public static void createToolBarGroups(IToolBarManager toolbar) { toolbar.add(new Separator(IContextMenuConstants.GROUP_NEW)); toolbar.add(new GroupMarker(IContextMenuConstants.GROUP_SHOW)); toolbar.add(new GroupMarker(IContextMenuConstants.GROUP_OPEN)); toolbar.add(new Separator(IContextMenuConstants.GROUP_BUILD)); toolbar.add(new Separator(IContextMenuConstants.GROUP_REORGANIZE)); toolbar.add(new Separator(IContextMenuConstants.GROUP_EDIT)); toolbar.add(new GroupMarker(IContextMenuConstants.GROUP_REMOVE_MATCHES)); toolbar.add(new GroupMarker(IContextMenuConstants.GROUP_GENERATE)); toolbar.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); toolbar.add(new Separator(IContextMenuConstants.GROUP_VIEWER_SETUP)); toolbar.add(new Separator(IContextMenuConstants.GROUP_PROPERTIES)); toolbar.add(new Separator(IContextMenuConstants.GROUP_SEARCH)); } private HashMap<DummyPart, IPageBookViewPage> fPartsToPages; private HashMap<IPageBookViewPage, DummyPart> fPagesToParts; private HashMap<ISearchResult, Object> fSearchViewStates; private SearchPageRegistry fSearchViewPageService; private SearchHistoryDropDownAction fSearchesDropDownAction; private ISearchResult fCurrentSearch; private DummyPart fDefaultPart; private SearchAgainAction fSearchAgainAction; private CancelSearchAction fCancelAction; private UndoRedoActionGroup fUndoRedoActionGroup; private IMemento fPageState; private int fActivationCount = 0; private String fDefaultPartName; private Composite fPageContent; private Link fDescription; private Composite fDescriptionComposite; public SearchView() { super(); fPartsToPages = new HashMap<DummyPart, IPageBookViewPage>(); fPagesToParts = new HashMap<IPageBookViewPage, DummyPart>(); fSearchViewPageService = new SearchPageRegistry(); fSearchViewStates = new HashMap<ISearchResult, Object>(); } @Override public void createPartControl(Composite parent) { createActions(); fPageContent = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(); layout.marginHeight = 0; layout.marginWidth = 0; layout.horizontalSpacing = 0; layout.verticalSpacing = 0; fPageContent.setLayout(layout); fDescriptionComposite = null; super.createPartControl(fPageContent); getPageBook().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); fDefaultPartName = getPartName(); initializeToolBar(); InternalSearchUI.getInstance().getSearchManager().addQueryListener(this); initializePageSwitcher(); PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, ISearchHelpContextIds.New_SEARCH_VIEW); restorePageFromMemento(); showLatestSearch(); } @Override public void dispose() { if (fUndoRedoActionGroup != null) { fUndoRedoActionGroup.dispose(); } InternalSearchUI.getInstance().getSearchViewManager().searchViewClosed(this); InternalSearchUI.getInstance().getSearchManager().removeQueryListener(this); super.dispose(); } @Override public void fillContextMenu(IMenuManager menuManager) { ISearchResult result = getCurrentSearchResult(); if (result != null) { menuManager.appendToGroup(IContextMenuConstants.GROUP_SEARCH, fSearchAgainAction); } } @Override public ISearchResultPage getActivePage() { IPage page = getCurrentPage(); if (page instanceof ISearchResultPage) { return (ISearchResultPage) page; } return null; } public ISearchResult getCurrentSearchResult() { return fCurrentSearch; } public IWorkbenchSiteProgressService getProgressService() { IWorkbenchSiteProgressService service = null; Object siteService = getSite().getAdapter(IWorkbenchSiteProgressService.class); if (siteService != null) { service = (IWorkbenchSiteProgressService) siteService; } return service; } /** * @return the search result page registry */ public SearchPageRegistry getSearchPageRegistry() { return fSearchViewPageService; } @Override public void init(IViewSite site, IMemento memento) throws PartInitException { super.init(site, memento); fPageState = memento; } @Override public void partActivated(IWorkbenchPart part) { super.partActivated(part); if (part == this) { InternalSearchUI.getInstance().getSearchViewManager().searchViewActivated(this); } } @Override public void queryAdded(ISearchQuery query) { fSearchesDropDownAction.updateEnablement(); } @Override public void queryFinished(ISearchQuery query) { if (fCurrentSearch != null && fCurrentSearch.equals(query.getSearchResult())) { updateCancelAction(); } } @Override public void queryRemoved(ISearchQuery query) { InternalSearchUI.getInstance().cancelSearch(query); if (query.getSearchResult().equals(fCurrentSearch)) { showSearchResult(null); partActivated(fDefaultPart); } fSearchViewStates.remove(query.getSearchResult()); fSearchesDropDownAction.disposeMenu(); fSearchesDropDownAction.updateEnablement(); } @Override public void queryStarting(ISearchQuery query) { if (fCurrentSearch != null && fCurrentSearch.equals(query.getSearchResult())) { updateCancelAction(); } } @Override public void saveState(IMemento memento) { for (Iterator<Entry<IPageBookViewPage, DummyPart>> iter = fPagesToParts.entrySet().iterator(); iter.hasNext();) { Entry<IPageBookViewPage, DummyPart> entry = iter.next(); ISearchResultPage page = (ISearchResultPage) entry.getKey(); DummyPart part = entry.getValue(); IMemento child = memento.createChild(MEMENTO_TYPE, page.getID()); page.saveState(child); child.putInteger(MEMENTO_KEY_LAST_ACTIVATION, part.getLastActivation()); } } /* * TODO workaround for focus problem. Clarify focus behavior. * * @see org.eclipse.ui.IWorkbenchPart#setFocus() */ @Override public void setFocus() { IPage currentPage = getCurrentPage(); if (currentPage != null) { currentPage.setFocus(); } else { super.setFocus(); } } @Override public void showBusy(boolean busy) { super.showBusy(busy); if (!busy) { getProgressService().warnOfContentChange(); } } public void showEmptySearchPage(String pageId) { ISearchResultPage newPage = fSearchViewPageService.findPageForPageId(pageId, true); internalShowSearchPage(newPage, null); } public void showSearchResult(ISearchResult search) { ISearchResultPage newPage = null; if (search != null) { newPage = fSearchViewPageService.findPageForSearchResult(search, true); if (newPage == null) { String format = SearchMessages.SearchView_error_noResultPage; String message = MessageFormat.format(format, new Object[] {search.getClass().getName()}); SearchPlugin.log(new Status(IStatus.ERROR, SearchPlugin.getID(), 0, message, null)); return; } } internalShowSearchPage(newPage, search); } @Override public void updateLabel() { ISearchResultPage page = getActivePage(); String label = ""; //$NON-NLS-1$ if (page != null) { label = LegacyActionTools.escapeMnemonics(page.getLabel()); } if (!fPageContent.isDisposed()) { if (label.length() == 0) { if (fDescriptionComposite != null) { fDescriptionComposite.dispose(); fDescriptionComposite = null; fPageContent.layout(); } } else { if (fDescriptionComposite == null) { fDescriptionComposite = new Composite(fPageContent, SWT.NONE); fDescriptionComposite.moveAbove(null); GridLayout layout = new GridLayout(); layout.marginHeight = 0; layout.marginWidth = 0; layout.verticalSpacing = 0; fDescriptionComposite.setLayout(layout); fDescriptionComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); fDescription = new Link(fDescriptionComposite, SWT.NONE); GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, false); gridData.horizontalIndent = 5; fDescription.setLayoutData(gridData); fDescription.setText(label); Label separator = new Label(fDescriptionComposite, SWT.SEPARATOR | SWT.HORIZONTAL); separator.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); fPageContent.layout(); } else { fDescription.setText(label); } } } } public void updatePartName() { if (fDefaultPartName != null) { // mstodo not yet enabled. // String partName= null; // ISearchResultPage page= getActivePage(); // if (page != null && isPinned()) { // partName= getSearchPageRegistry().findLabelForPageId(page.getID()); // } // setPartName(partName != null ? partName : fDefaultPartName); } } @Override protected IPage createDefaultPage(PageBook book) { IPageBookViewPage page = new EmptySearchView(); page.createControl(book); initPage(page); DummyPart part = new DummyPart(); fPartsToPages.put(part, page); fPagesToParts.put(page, part); fDefaultPart = part; return page; } @Override protected PageRec doCreatePage(IWorkbenchPart part) { IPageBookViewPage page = fPartsToPages.get(part); initPage(page); page.createControl(getPageBook()); PageRec rec = new PageRec(part, page); return rec; } @Override protected void doDestroyPage(IWorkbenchPart part, PageRec pageRecord) { IPage page = pageRecord.page; page.dispose(); pageRecord.dispose(); // empty cross-reference cache fPartsToPages.remove(part); } // Methods related to saving page state. ------------------------------------------- @Override protected IWorkbenchPart getBootstrapPart() { return null; } @Override protected void initPage(IPageBookViewPage page) { super.initPage(page); IActionBars actionBars = page.getSite().getActionBars(); actionBars.setGlobalActionHandler(ActionFactory.REFRESH.getId(), fSearchAgainAction); actionBars.updateActionBars(); fUndoRedoActionGroup.fillActionBars(actionBars); ISearchResultPage srPage = (ISearchResultPage) page; IMemento memento = null; if (fPageState != null) { IMemento[] mementos = fPageState.getChildren(MEMENTO_TYPE); for (int i = 0; i < mementos.length; i++) { if (mementos[i].getID().equals(srPage.getID())) { memento = mementos[i]; break; } } } srPage.restoreState(memento); } @Override protected boolean isImportant(IWorkbenchPart part) { return part instanceof DummyPart; } private void createActions() { fSearchesDropDownAction = new SearchHistoryDropDownAction(this); fSearchesDropDownAction.updateEnablement(); fSearchAgainAction = new SearchAgainAction(this); fSearchAgainAction.setEnabled(false); fSearchAgainAction.setActionDefinitionId(IWorkbenchCommandConstants.FILE_REFRESH); fCancelAction = new CancelSearchAction(this); fCancelAction.setEnabled(false); IUndoContext workspaceContext = (IUndoContext) ResourcesPlugin.getWorkspace().getAdapter( IUndoContext.class); fUndoRedoActionGroup = new UndoRedoActionGroup(getViewSite(), workspaceContext, true); } private void initializePageSwitcher() { new PageSwitcher(this) { @Override public void activatePage(Object page) { ISearchResult searchResult = ((ISearchQuery) page).getSearchResult(); InternalSearchUI.getInstance().showSearchResult(SearchView.this, searchResult, false); } @Override public ImageDescriptor getImageDescriptor(Object page) { ISearchResult searchResult = ((ISearchQuery) page).getSearchResult(); return searchResult.getImageDescriptor(); } @Override public String getName(Object page) { ISearchResult searchResult = ((ISearchQuery) page).getSearchResult(); return searchResult.getLabel(); } @Override public Object[] getPages() { return NewSearchUI.getQueries(); } }; } private void initializeToolBar() { IToolBarManager tbm = getViewSite().getActionBars().getToolBarManager(); createToolBarGroups(tbm); tbm.appendToGroup(IContextMenuConstants.GROUP_SEARCH, fSearchAgainAction); tbm.appendToGroup(IContextMenuConstants.GROUP_SEARCH, fCancelAction); tbm.appendToGroup(IContextMenuConstants.GROUP_SEARCH, fSearchesDropDownAction); getViewSite().getActionBars().updateActionBars(); } private void internalShowSearchPage(ISearchResultPage page, ISearchResult search) { // detach the previous page. ISearchResultPage currentPage = (ISearchResultPage) getCurrentPage(); if (fCurrentSearch != null && currentPage != null) { fSearchViewStates.put(fCurrentSearch, currentPage.getUIState()); currentPage.setInput(null, null); } fCurrentSearch = search; if (page != null) { if (page != currentPage) { DummyPart part = fPagesToParts.get(page); if (part == null) { part = new DummyPart(); fPagesToParts.put(page, part); fPartsToPages.put(part, page); page.setViewPart(this); } part.setLastActivation(++fActivationCount); partActivated(part); } // connect to the new pages Object uiState = search != null ? fSearchViewStates.get(search) : null; page.setInput(search, uiState); } updatePartName(); updateLabel(); updateCancelAction(); updateHelpContextID(page); } private void restorePageFromMemento() { if (fPageState != null) { int bestActivation = -1; IMemento restorePageMemento = null; IMemento[] children = fPageState.getChildren(MEMENTO_TYPE); for (int i = 0; i < children.length; i++) { IMemento pageMemento = children[i]; if (pageMemento.getString(MEMENTO_KEY_RESTORE) != null) { Integer lastActivation = pageMemento.getInteger(MEMENTO_KEY_LAST_ACTIVATION); if (lastActivation != null && lastActivation.intValue() > bestActivation) { bestActivation = lastActivation.intValue(); restorePageMemento = pageMemento; } } } if (restorePageMemento != null) { showEmptySearchPage(restorePageMemento.getID()); } } } private void showLatestSearch() { ISearchQuery[] queries = InternalSearchUI.getInstance().getSearchManager().getQueries(); if (queries.length > 0) { showSearchResult(queries[0].getSearchResult()); } } private void updateCancelAction() { ISearchResult result = getCurrentSearchResult(); boolean queryRunning = false; if (result != null) { queryRunning = InternalSearchUI.getInstance().isQueryRunning(result.getQuery()); } fCancelAction.setEnabled(queryRunning); fSearchAgainAction.setEnabled(!queryRunning && result != null && result.getQuery().canRerun()); } private void updateHelpContextID(ISearchResultPage page) { String helpContextId = null; String pageId = null; if (page != null) { pageId = page.getID(); } if (pageId != null) { helpContextId = fSearchViewPageService.getHelpContextId(pageId); } if (helpContextId == null) { helpContextId = ISearchHelpContextIds.New_SEARCH_VIEW; } PlatformUI.getWorkbench().getHelpSystem().setHelp(fPageContent.getParent(), helpContextId); } }