diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/IFindReplaceTargetExtension5.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/IFindReplaceTargetExtension5.java new file mode 100644 index 00000000000..7724bddb98e --- /dev/null +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/text/IFindReplaceTargetExtension5.java @@ -0,0 +1,43 @@ +package org.eclipse.jface.text; + +import org.eclipse.swt.widgets.Composite; + +/** + * Extension to search and replace using an "inline"-Find replace Bar. In order for this inline + * find-replace bar to work, inheriting panes need to provide a way to inject a "toolbar". + * + * In the future, extension could be elevated to a "IInlineToolBarExtension", in case there are + * other tools that want to profit from this extension + * + * @since 3.24 + */ +public interface IFindReplaceTargetExtension5 { + + /** + * This is called every time the inline find-replace dialog is to be shown. The implementing + * class guarantees to then provide a composite onto which the inline search is drawn. + * + * The composite is expected to have a GridLayout with a single column. Neither the width nor + * the height are specified (XXX ?). + * + * TODO: I'm unhappy with the name, but it seems consistent with the current status Quo defined + * in IFindReplaceTargetExtension + * + * @return the composite the inline find-replace dialog may draw on + */ + public Composite beginInlineSession(); + + /** + * Updates the layout of the implementing class. Is required, for example, when the + * "replace"-dropdown is opened/closed + * + * TODO: I'd like to avoid having this method. Is there a better way? + */ + public void updateLayout(); + + /** + * The implementing class may now dispose of the composite created in beginInlineSession. + * + */ + public void endInlineSession(); +} diff --git a/bundles/org.eclipse.ui.ide/.project b/bundles/org.eclipse.ui.ide/.project index f9de5f0ac41..c663fbbf333 100644 --- a/bundles/org.eclipse.ui.ide/.project +++ b/bundles/org.eclipse.ui.ide/.project @@ -37,6 +37,13 @@ org.eclipse.jdt.core.javanature org.eclipse.pde.api.tools.apiAnalysisNature + + + src/org/eclipse/ui/internal/views/markers/search-feature + 2 + C:/Users/mwittmer/Documents/search-feature + + 1676382308432 diff --git a/bundles/org.eclipse.ui.ide/META-INF/MANIFEST.MF b/bundles/org.eclipse.ui.ide/META-INF/MANIFEST.MF index 959d5c2fd13..d6c085fd9ef 100644 --- a/bundles/org.eclipse.ui.ide/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.ui.ide/META-INF/MANIFEST.MF @@ -63,7 +63,8 @@ Require-Bundle: org.eclipse.core.resources;bundle-version="[3.19.0,4.0.0)";resol org.eclipse.e4.ui.ide;bundle-version="[3.15.0,4.0.0)";visibility:=reexport, org.eclipse.e4.core.di;bundle-version="[1.9.0,2.0.0)", org.eclipse.e4.core.di.extensions;bundle-version="[0.18.0,1.0.0)", - org.eclipse.ui.navigator;bundle-version="3.12.0" + org.eclipse.ui.navigator;bundle-version="3.12.0", + org.eclipse.ui.workbench.texteditor Import-Package: javax.annotation;version="[1.3.0,2.0.0)", javax.inject;version="[1.0.0,2.0.0)", org.osgi.service.event;version="[1.4.0,2.0.0)" diff --git a/bundles/org.eclipse.ui.ide/plugin.xml b/bundles/org.eclipse.ui.ide/plugin.xml index b170640a475..0e9523e8850 100644 --- a/bundles/org.eclipse.ui.ide/plugin.xml +++ b/bundles/org.eclipse.ui.ide/plugin.xml @@ -1089,7 +1089,13 @@ id="org.eclipse.ui.ide.markers.copyMarkerResourceQualifiedName" name="%command.copyMarkerResourceQualifiedName.name" defaultHandler="org.eclipse.ui.internal.views.markers.CopyMarkerResourceQualifiedNameHandler"> - + + + + + + * * @since 3.4 * */ -public class ExtendedMarkersView extends ViewPart { +public class ExtendedMarkersView extends ViewPart implements IFindReplaceTarget, IFindReplaceTargetExtension5 { /** * The Markers View Update Job Family + * * @since 3.6 */ public final Object MARKERSVIEW_UPDATE_JOB_FAMILY = new Object(); @@ -162,16 +175,20 @@ public class ExtendedMarkersView extends ViewPart { private UIUpdateJob uiUpdateJob; + private Composite parentComposite; + private Composite viewerComposite; + private Composite findComposite; private MarkersTreeViewer viewer; private Action filterAction; - + private FindReplaceAction findReplaceAction; /** * Tells whether the tree has been painted. + * * @since 3.7 */ - private boolean treePainted= false; + private boolean treePainted = false; private ISelectionListener pageSelectionListener; private IPartListener2 partListener; @@ -183,21 +200,18 @@ public class ExtendedMarkersView extends ViewPart { private RedoActionHandler redoAction; - private boolean isViewVisible= true; - + private boolean isViewVisible = true; /** * Return a new instance of the receiver. * - * @param contentGeneratorId - * the id of the generator to load. + * @param contentGeneratorId the id of the generator to load. */ public ExtendedMarkersView(String contentGeneratorId) { super(); defaultGeneratorIds = new String[] { contentGeneratorId }; } - /** * Add all concrete {@link MarkerSupportItem} elements associated with the * receiver to allMarkers. @@ -205,8 +219,7 @@ public ExtendedMarkersView(String contentGeneratorId) { * @param markerItem * @param allMarkers */ - private void addAllConcreteItems(MarkerSupportItem markerItem, - Collection allMarkers) { + private void addAllConcreteItems(MarkerSupportItem markerItem, Collection allMarkers) { if (markerItem.isConcrete()) { allMarkers.add(markerItem); return; @@ -233,8 +246,7 @@ void addExpandedCategory(MarkerCategory category) { * Add all of the markers in markerItem recursively. * * @param markerItem - * @param allMarkers - * {@link Collection} of {@link IMarker} + * @param allMarkers {@link Collection} of {@link IMarker} */ private void addMarkers(MarkerSupportItem markerItem, Collection allMarkers) { if (markerItem.getMarker() != null) @@ -255,8 +267,8 @@ private void addMarkers(MarkerSupportItem markerItem, Collection allMar private void createViewer(Composite parent) { parent.setLayout(new FillLayout()); - viewer = new MarkersTreeViewer(new Tree(parent, SWT.H_SCROLL - /*| SWT.VIRTUAL */| SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION)); + viewer = new MarkersTreeViewer( + new Tree(parent, SWT.H_SCROLL/* | SWT.VIRTUAL */ | SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION)); WorkbenchViewerSetup.setupViewer(viewer); viewer.getTree().setLinesVisible(true); viewer.setUseHashlookup(true); @@ -270,7 +282,7 @@ private void createViewer(Composite parent) { viewer.getTree().addPaintListener(new PaintListener() { @Override public void paintControl(PaintEvent e) { - treePainted= true; + treePainted = true; viewer.getTree().removePaintListener(this); } }); @@ -279,8 +291,7 @@ public void paintControl(PaintEvent e) { /** * Create the columns for the receiver. * - * @param currentColumns - * the columns to refresh + * @param currentColumns the columns to refresh * @param widths */ private void createColumns(TreeColumn[] currentColumns, int[] widths) { @@ -306,8 +317,7 @@ private void createColumns(TreeColumn[] currentColumns, int[] widths) { // Show the help in the first column column.setLabelProvider(new MarkerColumnLabelProvider(markerField)); column.getColumn().setText(markerField.getColumnHeaderText()); - column.getColumn().setToolTipText( - markerField.getColumnTooltipText()); + column.getColumn().setToolTipText(markerField.getColumnTooltipText()); column.getColumn().setImage(markerField.getColumnHeaderImage()); EditingSupport support = markerField.getEditingSupport(viewer); @@ -318,24 +328,23 @@ private void createColumns(TreeColumn[] currentColumns, int[] widths) { updateDirectionIndicator(column.getColumn(), markerField); IMemento columnWidths = null; - if (memento != null){ + if (memento != null) { columnWidths = memento.getChild(TAG_COLUMN_WIDTHS); } - //adjust the column width + // adjust the column width int columnWidth = i < widths.length ? widths[i] : -1; columnWidth = getFieldWidth(markerField, columnWidth, false); if (columnWidths != null) { // save it columnWidths.putInteger( - markerField.getConfigurationElement().getAttribute( - MarkerSupportInternalUtilities.ATTRIBUTE_ID), columnWidth); + markerField.getConfigurationElement().getAttribute(MarkerSupportInternalUtilities.ATTRIBUTE_ID), + columnWidth); } // Take trim into account if we are using the default value, but not // if it is restored. if (columnWidth < 0) - layout.addColumnData(new ColumnPixelData(markerField - .getDefaultColumnWidth(tree), true, true)); + layout.addColumnData(new ColumnPixelData(markerField.getDefaultColumnWidth(tree), true, true)); else layout.addColumnData(new ColumnPixelData(columnWidth, true)); } @@ -385,7 +394,7 @@ int getFieldWidth(MarkerField markerField, int preferredWidth, boolean considerU Tree tree = getViewer().getTree(); if (considerUIWidths) { - TreeColumn[] columns= tree.getColumns(); + TreeColumn[] columns = tree.getColumns(); for (TreeColumn column : columns) { if (markerField.equals(column.getData(MARKER_FIELD))) { return column.getWidth(); @@ -396,9 +405,8 @@ int getFieldWidth(MarkerField markerField, int preferredWidth, boolean considerU if (preferredWidth < 0 && memento != null) { IMemento columnWidths = memento.getChild(TAG_COLUMN_WIDTHS); if (columnWidths != null) { - Integer value = columnWidths.getInteger(markerField - .getConfigurationElement().getAttribute( - MarkerSupportInternalUtilities.ATTRIBUTE_ID)); + Integer value = columnWidths.getInteger(markerField.getConfigurationElement() + .getAttribute(MarkerSupportInternalUtilities.ATTRIBUTE_ID)); // Make sure we get a useful value if (value != null && value.intValue() >= 0) preferredWidth = value.intValue(); @@ -419,7 +427,23 @@ int getFieldWidth(MarkerField markerField, int preferredWidth, boolean considerU @Override public void createPartControl(Composite parent) { - createViewer(parent); + parentComposite = new Composite(parent, SWT.NULL); + GridLayout parentCompositeLayout = new GridLayout(1, true); + parentCompositeLayout.marginBottom = 0; + parentCompositeLayout.verticalSpacing = 0; + parentCompositeLayout.horizontalSpacing = 0; + parentComposite.setLayout(parentCompositeLayout); + + viewerComposite = new Composite(parentComposite, SWT.NULL); + GridData viewerCompositeGD = new GridData(); + viewerCompositeGD.grabExcessHorizontalSpace = true; + viewerCompositeGD.grabExcessVerticalSpace = true; + viewerCompositeGD.horizontalAlignment = GridData.FILL; + viewerCompositeGD.verticalAlignment = GridData.FILL; + viewerComposite.setLayout(new FillLayout()); + viewerComposite.setLayoutData(viewerCompositeGD); + + createViewer(viewerComposite); addDoubleClickListener(); @@ -441,15 +465,14 @@ public void createPartControl(Composite parent) { getSite().setSelectionProvider(viewer); - IUndoContext undoContext= getUndoContext(); - undoAction= new UndoActionHandler(getSite(), undoContext); + IUndoContext undoContext = getUndoContext(); + undoAction = new UndoActionHandler(getSite(), undoContext); undoAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_UNDO); - redoAction= new RedoActionHandler(getSite(), undoContext); + redoAction = new RedoActionHandler(getSite(), undoContext); redoAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_REDO); getViewSite().getActionBars().setGlobalActionHandler(ActionFactory.UNDO.getId(), undoAction); getViewSite().getActionBars().setGlobalActionHandler(ActionFactory.REDO.getId(), redoAction); - startView(); } @@ -459,7 +482,7 @@ public void createPartControl(Composite parent) { */ private void startView() { viewer.setInput(builder.getMarkers()); - //always use a clone for Thread safety + // always use a clone for Thread safety IContentProvider contentProvider = viewer.getContentProvider(); Markers clone = createViewerInputClone(); if (clone == null) { @@ -470,17 +493,19 @@ private void startView() { } /** - * Attaches an {@link IDoubleClickListener} to expand items that are not openable + * Attaches an {@link IDoubleClickListener} to expand items that are not + * openable + * * @since 3.8 */ private void addDoubleClickListener() { viewer.addDoubleClickListener(event -> { ISelection selection = event.getSelection(); - if(selection instanceof ITreeSelection) { + if (selection instanceof ITreeSelection) { ITreeSelection ss = (ITreeSelection) selection; - if(ss.size() == 1) { + if (ss.size() == 1) { Object obj = ss.getFirstElement(); - if(viewer.isExpandable(obj)) { + if (viewer.isExpandable(obj)) { viewer.setExpandedState(obj, !viewer.getExpandedState(obj)); } } @@ -508,8 +533,8 @@ private void addPageAndPartSelectionListener() { private void addSelectionListener() { viewer.addSelectionChangedListener(event -> { ISelection selection = event.getSelection(); - if (selection instanceof IStructuredSelection){ - updateStatusLine((IStructuredSelection)selection); + if (selection instanceof IStructuredSelection) { + updateStatusLine((IStructuredSelection) selection); } }); } @@ -577,7 +602,8 @@ protected void open(ISelection selection, boolean activate) { /** * Returns the complete list of selected {@link IMarker}s from the view. * - * @return the complete list of selected {@link IMarker}s or an empty array, never null + * @return the complete list of selected {@link IMarker}s or an empty array, + * never null * @since 3.8 */ IMarker[] getOpenableMarkers() { @@ -631,7 +657,7 @@ public void dispose() { * @return MarkerSupportItem[] */ MarkerSupportItem[] getAllConcreteItems() { - MarkerSupportItem[] elements =getActiveViewerInputClone().getElements(); + MarkerSupportItem[] elements = getActiveViewerInputClone().getElements(); Collection allMarkers = new ArrayList<>(); for (MarkerSupportItem element : elements) { addAllConcreteItems(element, allMarkers); @@ -656,7 +682,7 @@ Collection getAllFilters() { * @return IMarker[] */ IMarker[] getAllMarkers() { - MarkerSupportItem[] elements =getActiveViewerInputClone().getElements(); + MarkerSupportItem[] elements = getActiveViewerInputClone().getElements(); Collection allMarkers = new ArrayList<>(); for (MarkerSupportItem element : elements) { addMarkers(element, allMarkers); @@ -688,7 +714,7 @@ Collection getCategoriesToExpand() { IMemento expanded = this.memento.getChild(TAG_EXPANDED); if (expanded != null) { IMemento[] mementoCategories = expanded.getChildren(TAG_CATEGORY); - MarkerCategory[] markerCategories =getActiveViewerInputClone().getCategories(); + MarkerCategory[] markerCategories = getActiveViewerInputClone().getCategories(); if (markerCategories != null) { for (MarkerCategory markerCategorie : markerCategories) { for (IMemento mementoCategorie : mementoCategories) { @@ -742,9 +768,8 @@ private IContentProvider getContentProvider() { * @return String */ private String getFieldId(TreeColumn treeColumn) { - return ((MarkerField) treeColumn.getData(MARKER_FIELD)) - .getConfigurationElement().getAttribute( - MarkerSupportInternalUtilities.ATTRIBUTE_ID); + return ((MarkerField) treeColumn.getData(MARKER_FIELD)).getConfigurationElement() + .getAttribute(MarkerSupportInternalUtilities.ATTRIBUTE_ID); } /** @@ -771,8 +796,7 @@ private SelectionListener getHeaderListener() { public void widgetSelected(SelectionEvent e) { final TreeColumn column = (TreeColumn) e.widget; - final MarkerField field = (MarkerField) column - .getData(MARKER_FIELD); + final MarkerField field = (MarkerField) column.getData(MARKER_FIELD); setPrimarySortField(field, column); } }; @@ -850,8 +874,8 @@ public void partVisible(IWorkbenchPartReference partRef) { } /** - * @return true if the builder noticed that marker updates were made - * but UI is not updated yet + * @return true if the builder noticed that marker updates were made but UI is + * not updated yet */ private boolean hasPendingChanges() { boolean[] changeFlags = builder.readChangeFlags(); @@ -908,8 +932,8 @@ public boolean getSortAscending() { * Get the status message for the title and status line. * * @param markers the markers for which to get the status message - * @param counts an array of {@link Integer} where index indicates - * [errors,warnings,infos,others] + * @param counts an array of {@link Integer} where index indicates + * [errors,warnings,infos,others] * @return String */ private String getStatusMessage(Markers markers, Integer[] counts) { @@ -930,7 +954,7 @@ private String getStatusMessage(Markers markers, Integer[] counts) { } filteredCount += childCount; } - } else if(markerLimitsEnabled) { + } else if (markerLimitsEnabled) { filteredCount = markerLimit; } else { filteredCount = -1; @@ -945,9 +969,8 @@ private String getStatusMessage(Markers markers, Integer[] counts) { } return status; } - String message= MessageFormat.format( - MarkerMessages.errorsAndWarningsSummaryBreakdown, - counts[0], counts[1], /* combine infos and others */ counts[2] + counts[3]); + String message = MessageFormat.format(MarkerMessages.errorsAndWarningsSummaryBreakdown, counts[0], counts[1], + /* combine infos and others */ counts[2] + counts[3]); if (filteredCount < 0 || filteredCount >= totalCount) { return message; } @@ -963,20 +986,24 @@ private String getStatusMessage(Markers markers, Integer[] counts) { Markers getViewerInput() { return (Markers) viewer.getInput(); } + /** * Return the active clone currently in use by UI. * * @return Object */ Markers getActiveViewerInputClone() { - /*The ideal place to hold the reference for the - clone is the view,as it is a for-ui-only clone*/ + /* + * The ideal place to hold the reference for the clone is the view,as it is a + * for-ui-only clone + */ return builder.getClonedMarkers(); } /** - * Return a new clone to use in UI.Can return - * null if markers are changing or building. + * Return a new clone to use in UI.Can return null if markers are changing or + * building. + * * @see CachedMarkerBuilder#createMarkersClone() * * @@ -1005,16 +1032,14 @@ public void init(IViewSite site, IMemento m) throws PartInitException { } if (generatorDescriptor == null && defaultGeneratorIds.length > 0) { - generatorDescriptor = MarkerSupportRegistry.getInstance() - .getContentGenDescriptor(defaultGeneratorIds[0]); + generatorDescriptor = MarkerSupportRegistry.getInstance().getContentGenDescriptor(defaultGeneratorIds[0]); if (generatorDescriptor == null) { logInvalidGenerator(defaultGeneratorIds[0]); } } if (generatorDescriptor == null) { - generatorDescriptor = MarkerSupportRegistry.getInstance() - .getDefaultContentGenDescriptor(); + generatorDescriptor = MarkerSupportRegistry.getInstance().getDefaultContentGenDescriptor(); } builder = new CachedMarkerBuilder(this); @@ -1026,11 +1051,9 @@ public void init(IViewSite site, IMemento m) throws PartInitException { // Add in the markers view actions - menuService.populateContributionManager((ContributionManager) site - .getActionBars().getMenuManager(), "menu:" //$NON-NLS-1$ + menuService.populateContributionManager((ContributionManager) site.getActionBars().getMenuManager(), "menu:" //$NON-NLS-1$ + MarkerSupportRegistry.MARKERS_ID); - menuService.populateContributionManager((ContributionManager) site - .getActionBars().getToolBarManager(), + menuService.populateContributionManager((ContributionManager) site.getActionBars().getToolBarManager(), "toolbar:" + MarkerSupportRegistry.MARKERS_ID); //$NON-NLS-1$ builder.restoreState(m); @@ -1129,8 +1152,7 @@ MarkerContentGenerator getGenerator() { * @param id */ void logInvalidGenerator(String id) { - StatusManager.getManager().handle( - new Status(IStatus.WARNING, IDEWorkbenchPlugin.IDE_WORKBENCH, + StatusManager.getManager().handle(new Status(IStatus.WARNING, IDEWorkbenchPlugin.IDE_WORKBENCH, NLS.bind("Invalid markerContentGenerator {0} ", //$NON-NLS-1$ id))); } @@ -1139,8 +1161,8 @@ void logInvalidGenerator(String id) { * Open the filters dialog for the receiver. */ void openFiltersDialog() { - FiltersConfigurationDialog dialog = new FiltersConfigurationDialog( - getSite().getWorkbenchWindow().getShell(), generator); + FiltersConfigurationDialog dialog = new FiltersConfigurationDialog(getSite().getWorkbenchWindow().getShell(), + generator); if (dialog.open() == Window.OK) { generator.updateFilters(dialog.getFilters(), dialog.andFilters()); } @@ -1189,7 +1211,7 @@ public boolean isMarkerLimitsEnabled() { */ void reexpandCategories() { if (!getCategoriesToExpand().isEmpty() && builder.isShowingHierarchy()) { - MarkerItem[] items =getActiveViewerInputClone().getElements(); + MarkerItem[] items = getActiveViewerInputClone().getElements(); IContentProvider provider = viewer.getContentProvider(); for (int i = 0; i < items.length; i++) { String name = ((MarkerCategory) items[i]).getName(); @@ -1206,8 +1228,8 @@ void reexpandCategories() { } /** - * Register the context menu for the receiver so that commands may be added - * to it. + * Register the context menu for the receiver so that commands may be added to + * it. */ private void registerContextMenu() { MenuManager contextMenu = new MenuManager(); @@ -1251,16 +1273,16 @@ public void saveState(IMemento m) { int[] positions = viewer.getTree().getColumnOrder(); for (int i = 0; i < fields.length; i++) { TreeColumn column = viewer.getTree().getColumn(i); - MarkerField markerField= (MarkerField)column.getData(MARKER_FIELD); + MarkerField markerField = (MarkerField) column.getData(MARKER_FIELD); /* * Workaround for TeeColumn.getWidth() returning 0 in some cases, see * https://bugs.eclipse.org/341865 for details. */ - int width= getFieldWidth(markerField, -1, treePainted); + int width = getFieldWidth(markerField, -1, treePainted); columnEntry.putInteger(getFieldId(column), width); - fields[positions[i]]= markerField; + fields[positions[i]] = markerField; } if (generator != null) { generator.saveState(m, fields); @@ -1303,10 +1325,8 @@ void setPrimarySortField(MarkerField field) { return; } } - StatusManager.getManager().handle( - StatusUtil.newStatus(IStatus.WARNING, - "Sorting by non visible field " //$NON-NLS-1$ - + field.getName(), null)); + StatusManager.getManager().handle(StatusUtil.newStatus(IStatus.WARNING, "Sorting by non visible field " //$NON-NLS-1$ + + field.getName(), null)); } /** @@ -1333,8 +1353,7 @@ void setSelection(StructuredSelection structuredSelection, boolean reveal) { List newSelection = new ArrayList<>(structuredSelection.size()); for (Object next : structuredSelection) { if (next instanceof IMarker) { - MarkerItem marker = builder.getMarkers().getMarkerItem( - (IMarker) next); + MarkerItem marker = builder.getMarkers().getMarkerItem((IMarker) next); if (marker != null) { newSelection.add(marker); } @@ -1450,7 +1469,7 @@ void updateTitle() { * Updates this view's title image. * * @param counts an array of {@link Integer} where index indicates - * [errors,warnings,infos,others] + * [errors,warnings,infos,others] * @since 3.7 */ void updateTitleImage(Integer[] counts) { @@ -1461,8 +1480,7 @@ void updateTitleImage(Integer[] counts) { */ private void initDragAndDrop() { int operations = DND.DROP_COPY; - Transfer[] transferTypes = new Transfer[] { - MarkerTransfer.getInstance(), TextTransfer.getInstance() }; + Transfer[] transferTypes = new Transfer[] { MarkerTransfer.getInstance(), TextTransfer.getInstance() }; DragSourceListener listener = new DragSourceAdapter() { @Override public void dragSetData(DragSourceEvent event) { @@ -1483,14 +1501,16 @@ public void dragFinished(DragSourceEvent event) { private void initToolBar() { IActionBars bars = getViewSite().getActionBars(); IToolBarManager tm = bars.getToolBarManager(); + setFindReplaceAction( + new FindReplaceAction(EditorMessages.getBundleForConstructedKeys(), "MarkersView.Find.", this)); //$NON-NLS-1$ createFilterAction(); tm.add(new Separator("FilterGroup")); //$NON-NLS-1$ tm.add(filterAction); } /** - * The user is attempting to drag marker data. Add the appropriate data to - * the event depending on the transfer type. + * The user is attempting to drag marker data. Add the appropriate data to the + * event depending on the transfer type. */ private void performDragSetData(DragSourceEvent event) { if (MarkerTransfer.getInstance().isSupportedType(event.dataType)) { @@ -1517,10 +1537,10 @@ Object[] getHiddenFields() { /** * @param visible */ - void setVisibleFields(Collection visible,int[] widths) { + void setVisibleFields(Collection visible, int[] widths) { generator.setVisibleFields(visible); - //viewer.setSelection(new StructuredSelection()); - //viewer.removeAndClearAll(); + // viewer.setSelection(new StructuredSelection()); + // viewer.removeAndClearAll(); createColumns(viewer.getTree().getColumns(), widths); scheduleUpdate(0L); } @@ -1533,8 +1553,7 @@ TreeViewer getViewer() { } /** - * The method should not be called directly, see - * {@link MarkerUpdateScheduler} + * The method should not be called directly, see {@link MarkerUpdateScheduler} * * Cancel a scheduled delay */ @@ -1547,8 +1566,7 @@ void cancelQueuedUpdates() { } /** - * The method should not be called directly, see - * {@link MarkerUpdateScheduler} + * The method should not be called directly, see {@link MarkerUpdateScheduler} * * @param delay * @return UIUpdateJob @@ -1563,8 +1581,7 @@ UIUpdateJob scheduleUpdate(long delay) { // uiUpdateJob.setPriority(Job.SHORT); uiUpdateJob.setSystem(true); } - IWorkbenchSiteProgressService progressService = builder - .getProgressService(); + IWorkbenchSiteProgressService progressService = builder.getProgressService(); if (progressService != null) { progressService.schedule(uiUpdateJob, delay); } else { @@ -1584,23 +1601,24 @@ long getLastUIRefreshTime() { } return -1; } + /** * @return true if the UI isUpdating * */ boolean isUIUpdating() { - return uiUpdateJob!=null?uiUpdateJob.isUpdating():false; + return uiUpdateJob != null ? uiUpdateJob.isUpdating() : false; } /** - * Return the next secondary id that has not been opened for a primary id of - * a part. + * Return the next secondary id that has not been opened for a primary id of a + * part. * * @return part */ static String newSecondaryID(IViewPart part) { - while (part.getSite().getPage().findViewReference( - part.getSite().getId(), String.valueOf(instanceCount)) != null) { + while (part.getSite().getPage().findViewReference(part.getSite().getId(), + String.valueOf(instanceCount)) != null) { instanceCount++; } @@ -1711,9 +1729,9 @@ public void selectionChanged(IWorkbenchPart part, ISelection selection) { } /** - * Return the undo context associated with operations performed in this view. By default, return - * the workspace undo context. Subclasses should override if a more specific undo context should - * be used. + * Return the undo context associated with operations performed in this view. By + * default, return the workspace undo context. Subclasses should override if a + * more specific undo context should be used. * * @since 3.7 */ @@ -1729,16 +1747,19 @@ protected IUndoContext getUndoContext() { */ protected String getDeleteOperationName(IMarker[] markers) { Assert.isLegal(markers.length > 0); - return markers.length == 1 ? MarkerMessages.deleteMarker_operationName : MarkerMessages.deleteMarkers_operationName; + return markers.length == 1 ? MarkerMessages.deleteMarker_operationName + : MarkerMessages.deleteMarkers_operationName; } /** * Tells whether this view is visible. *

- * See bug 401632 why we can't use {@link IWorkbenchPage#isPartVisible(IWorkbenchPart)}. + * See bug 401632 why we can't use + * {@link IWorkbenchPage#isPartVisible(IWorkbenchPart)}. *

* - * @return true if this view is visible, false otherwise + * @return true if this view is visible, false + * otherwise */ boolean isVisible() { return isViewVisible; @@ -1751,4 +1772,110 @@ public T getAdapter(Class adapter) { } return super.getAdapter(adapter); } + + /** + * <-- for finding --> + */ + + @Override + public Composite beginInlineSession() { + findComposite = new Composite(parentComposite, SWT.NULL); + findComposite.setLayout(new GridLayout(1, false)); + GridData findCompositeGD = new GridData(); + findCompositeGD.horizontalAlignment = GridData.FILL; + findCompositeGD.verticalAlignment = GridData.FILL; + findComposite.setLayoutData(findCompositeGD); + + return findComposite; + } + + @Override + public void updateLayout() { + // TODO not sure which one of these three does what I want to do + parentComposite.layout(); + parentComposite.redraw(); + parentComposite.update(); + } + + @Override + public void endInlineSession() { + findComposite.dispose(); + findComposite = null; + } + + @Override + public boolean canPerformFind() { + // TODO Auto-generated method stub + return false; + } + + @Override + public int findAndSelect(int widgetOffset, String findString, boolean searchForward, boolean caseSensitive, + boolean wholeWord) { + + var tree = viewer.getTree(); + var items = tree.getItems(); + ArrayList selection = new ArrayList<>(); + for (var item : items) { + // TODO: has children? + for (var child : ((MarkerViewerContentProvider) viewer.getContentProvider()).getElements(item)) { + MarkerSupportItem[] markerCategoryChildren = ((MarkerCategory) child).getChildren(); + for (var markerSupportItem : markerCategoryChildren) { + String markerMessage = markerSupportItem.getMarker().getAttribute(IMarker.MESSAGE, + MarkerSupportInternalUtilities.UNKNOWN_ATRRIBTE_VALUE_STRING); + if (markerMessage.contains(findString)) { + ArrayList selectionPath = new ArrayList<>(); + selectionPath.add(item); + selectionPath.add(markerSupportItem); + selection.add(new TreePath(selectionPath.toArray())); + } + } + var text = ((ColumnLabelProvider) viewer.getLabelProvider(1)).getText(child); + System.out.println(text); + } + } + + viewer.setSelection(new TreeSelection(selection.toArray(new TreePath[0]))); + + // very messy! TODO revisit how inline findreplace works + return 0; + } + + @Override + public Point getSelection() { + + return new Point(0, 0); + } + + @Override + public String getSelectionText() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isEditable() { + // TODO Auto-generated method stub + return false; + } + + @Override + public void replaceSelection(String text) { + // TODO Auto-generated method stub + + } + + /** + * @return Returns the findReplaceAction. + */ + public FindReplaceAction getFindReplaceAction() { + return findReplaceAction; + } + + /** + * @param findReplaceAction The findReplaceAction to set. + */ + public void setFindReplaceAction(FindReplaceAction findReplaceAction) { + this.findReplaceAction = findReplaceAction; + } } \ No newline at end of file diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/views/markers/MarkerViewFindHandler.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/views/markers/MarkerViewFindHandler.java new file mode 100644 index 00000000000..5b0ba50d1e6 --- /dev/null +++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/views/markers/MarkerViewFindHandler.java @@ -0,0 +1,59 @@ +package org.eclipse.ui.internal.views.markers; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.IHandler; +import org.eclipse.core.commands.IHandlerListener; +import org.eclipse.core.expressions.IEvaluationContext; +import org.eclipse.ui.ISources; +import org.eclipse.ui.part.ViewPart; + +/** + * @since 3.4 + * + */ +public class MarkerViewFindHandler implements IHandler { + @Override + public void addHandlerListener(IHandlerListener handlerListener) { + // TODO Auto-generated method stub + + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + // Adapted from https://www.eclipse.org/forums/index.php/t/104714/ + Object appContextObj = event.getApplicationContext(); + if (appContextObj instanceof IEvaluationContext appContext) { + ViewPart viewPart = (ViewPart) appContext.getVariable(ISources.ACTIVE_PART_NAME); + ExtendedMarkersView mv = (ExtendedMarkersView) viewPart; + mv.getFindReplaceAction().run(); + } + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isEnabled() { + // TODO Auto-generated method stub + return true; + } + + @Override + public boolean isHandled() { + // TODO Auto-generated method stub + return true; + } + + @Override + public void removeHandlerListener(IHandlerListener handlerListener) { + // TODO Auto-generated method stub + + } + +} diff --git a/bundles/org.eclipse.ui.views/META-INF/MANIFEST.MF b/bundles/org.eclipse.ui.views/META-INF/MANIFEST.MF index 9c91b195646..7006d6133cd 100644 --- a/bundles/org.eclipse.ui.views/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.ui.views/META-INF/MANIFEST.MF @@ -15,3 +15,4 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)", org.eclipse.jface;bundle-version="[3.31.0,4.0.0)" Bundle-RequiredExecutionEnvironment: JavaSE-17 Automatic-Module-Name: org.eclipse.ui.views +Import-Package: org.eclipse.jface.text diff --git a/bundles/org.eclipse.ui.views/src/org/eclipse/ui/views/contentoutline/ContentOutline.java b/bundles/org.eclipse.ui.views/src/org/eclipse/ui/views/contentoutline/ContentOutline.java index 6df8ba29f38..82694084a21 100644 --- a/bundles/org.eclipse.ui.views/src/org/eclipse/ui/views/contentoutline/ContentOutline.java +++ b/bundles/org.eclipse.ui.views/src/org/eclipse/ui/views/contentoutline/ContentOutline.java @@ -20,6 +20,8 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; +import org.eclipse.jface.text.IFindReplaceTarget; +import org.eclipse.jface.text.IFindReplaceTargetExtension5; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; @@ -77,7 +79,8 @@ * @noinstantiate This class is not intended to be instantiated by clients. * @noextend This class is not intended to be subclassed by clients. */ -public class ContentOutline extends PageBookView implements ISelectionProvider, ISelectionChangedListener { +public class ContentOutline extends PageBookView + implements ISelectionProvider, ISelectionChangedListener, IFindReplaceTarget, IFindReplaceTargetExtension5 { /** * The plugin prefix. @@ -239,4 +242,53 @@ protected void showPageRec(PageRec pageRec) { } super.showPageRec(pageRec); } + + @Override + public boolean canPerformFind() { + // TODO Auto-generated method stub + return true; + } + + @Override + public int findAndSelect(int widgetOffset, String findString, boolean searchForward, boolean caseSensitive, + boolean wholeWord) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public String getSelectionText() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isEditable() { + // TODO Auto-generated method stub + return false; + } + + @Override + public void replaceSelection(String text) { + // TODO Auto-generated method stub + + } + + @Override + public Composite beginInlineSession() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void updateLayout() { + // TODO Auto-generated method stub + + } + + @Override + public void endInlineSession() { + // TODO Auto-generated method stub + + } } diff --git a/bundles/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF b/bundles/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF index 2981cc60e33..71bfd5e5390 100644 --- a/bundles/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.ui.workbench.texteditor/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.ui.workbench.texteditor; singleton:=true -Bundle-Version: 3.17.100.qualifier +Bundle-Version: 3.18.0.qualifier Bundle-Activator: org.eclipse.ui.internal.texteditor.TextEditorPlugin Bundle-ActivationPolicy: lazy Bundle-Vendor: %providerName @@ -29,6 +29,7 @@ Require-Bundle: org.eclipse.core.expressions;bundle-version="[3.4.100,4.0.0)", org.eclipse.jface.text;bundle-version="[3.19.0,4.0.0)", org.eclipse.swt;bundle-version="[3.107.0,4.0.0)", - org.eclipse.ui;bundle-version="[3.5.0,4.0.0)" + org.eclipse.ui;bundle-version="[3.5.0,4.0.0)", + org.eclipse.text Bundle-RequiredExecutionEnvironment: JavaSE-17 Automatic-Module-Name: org.eclipse.ui.workbench.texteditor diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.java index 9715d5c0e64..cb07b4ca0de 100644 --- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.java +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/EditorMessages.java @@ -21,8 +21,11 @@ /** * Helper class to get NLSed messages. + * + * @since 3.18 */ -final class EditorMessages extends NLS { +// TODO: I changed the visibility to public - need to change back - MW +public final class EditorMessages extends NLS { private static final String BUNDLE_FOR_CONSTRUCTED_KEYS= "org.eclipse.ui.texteditor.ConstructedEditorMessages";//$NON-NLS-1$ private static ResourceBundle fgBundleForConstructedKeys= ResourceBundle.getBundle(BUNDLE_FOR_CONSTRUCTED_KEYS); diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java index 5839928d3c8..b2d87b7f162 100644 --- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceAction.java @@ -26,6 +26,7 @@ import org.eclipse.jface.dialogs.PageChangedEvent; import org.eclipse.jface.text.IFindReplaceTarget; +import org.eclipse.jface.text.IFindReplaceTargetExtension5; import org.eclipse.ui.IPartListener2; import org.eclipse.ui.IPartService; @@ -99,7 +100,7 @@ public FindReplaceDialogStub(IWorkbenchPartSite site) { * @since 3.3 */ public FindReplaceDialogStub(Shell shell) { - fDialog= new FindReplaceDialog(shell); + fDialog = new FindReplaceDialog(shell); fDialog.create(); fDialog.getShell().addDisposeListener(this); } @@ -263,6 +264,8 @@ public FindReplaceAction(ResourceBundle bundle, String prefix, IWorkbenchPart wo super(bundle, prefix); Assert.isLegal(workbenchPart != null); fWorkbenchPart= workbenchPart; + fTarget = fWorkbenchPart.getAdapter(IFindReplaceTarget.class); + inlineDialog = new InlineFindReplaceComponent(fTarget, fWorkbenchPart); update(); } @@ -314,10 +317,16 @@ public FindReplaceAction(ResourceBundle bundle, String prefix, IWorkbenchWindow update(); } - @Override - public void run() { - if (fTarget == null) - return; + final static boolean MW_NEW_FIND_REPLACE = true; // TODO replace with a preference + + private InlineFindReplaceComponent inlineDialog; + + /** + * Implement the "old" style of find and replace, using an external Shell + * + * @since 3.18 + */ + public void showFindReplaceModal() { final FindReplaceDialog dialog; final boolean isEditable; @@ -352,10 +361,33 @@ public void run() { dialog.open(); } + + /** + * @since 3.18 + */ + public void showInlineSearchReplaceIfPossible() { + if (fWorkbenchPart instanceof IFindReplaceTargetExtension5) { + inlineDialog.toggleActive(); + } else { + showFindReplaceModal(); + } + } + @Override - public void update() { + public void run() { + if (fTarget == null) + return; - if(fShell == null){ + if (MW_NEW_FIND_REPLACE) { + showInlineSearchReplaceIfPossible(); + } else { + showFindReplaceModal(); + } + } + + @Override + public void update() { + if (fShell == null || MW_NEW_FIND_REPLACE) { if (fWorkbenchPart == null && fWorkbenchWindow != null) fWorkbenchPart= fWorkbenchWindow.getPartService().getActivePart(); diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceDialog.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceDialog.java index fae3682279a..89a45fadd65 100644 --- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceDialog.java +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplaceDialog.java @@ -150,7 +150,8 @@ public void modifyText(ModifyEvent e) { offset= offset + fIncrementalBaseLocation.y; fNeedsInitialFindBeforeReplace= false; - findAndSelect(offset, "", isForwardSearch(), isCaseSensitiveSearch(), isWholeWordSearch(), isRegExSearchAvailableAndChecked()); //$NON-NLS-1$ + updateFindReplacerSettings(); + fFindReplacer.findAndSelect(offset, ""); } else { performSearch(false, false, isForwardSearch()); } @@ -160,6 +161,8 @@ public void modifyText(ModifyEvent e) { } } + FindReplacer fFindReplacer; + /** The size of the dialogs search history. */ private static final int HISTORY_SIZE= 15; @@ -262,6 +265,7 @@ public FindReplaceDialog(Shell parentShell) { setShellStyle(getShellStyle() ^ SWT.APPLICATION_MODAL | SWT.MODELESS); setBlockOnOpen(false); + fFindReplacer = new FindReplacer(getShell(), fTarget); } @Override @@ -875,7 +879,7 @@ protected void buttonPressed(int buttonID) { private int findIndex(String findString, int startPosition, boolean forwardSearch, boolean caseSensitive, boolean wrapSearch, boolean wholeWord, boolean regExSearch, boolean beep) { if (forwardSearch) { - int index= findAndSelect(startPosition, findString, true, caseSensitive, wholeWord, regExSearch); + int index = fFindReplacer.findAndSelect(startPosition, findString); if (index == -1) { if (beep && okToUse(getShell())) @@ -883,14 +887,15 @@ private int findIndex(String findString, int startPosition, boolean forwardSearc if (wrapSearch) { statusMessage(EditorMessages.FindReplace_Status_wrapped_label); - index= findAndSelect(-1, findString, true, caseSensitive, wholeWord, regExSearch); + index = fFindReplacer.findAndSelect(-1, findString); } } return index; } // backward - int index= startPosition == 0 ? -1 : findAndSelect(startPosition - 1, findString, false, caseSensitive, wholeWord, regExSearch); + int index = startPosition == 0 ? -1 + : fFindReplacer.findAndSelect(startPosition - 1, findString); if (index == -1) { if (beep && okToUse(getShell())) @@ -898,32 +903,12 @@ private int findIndex(String findString, int startPosition, boolean forwardSearc if (wrapSearch) { statusMessage(EditorMessages.FindReplace_Status_wrapped_label); - index= findAndSelect(-1, findString, false, caseSensitive, wholeWord, regExSearch); + index = fFindReplacer.findAndSelect(-1, findString); } } return index; } - /** - * Searches for a string starting at the given offset and using the specified search - * directives. If a string has been found it is selected and its start offset is - * returned. - * - * @param offset the offset at which searching starts - * @param findString the string which should be found - * @param forwardSearch the direction of the search - * @param caseSensitive true performs a case sensitive search, false an insensitive search - * @param wholeWord if true only occurrences are reported in which the findString stands as a word by itself - * @param regExSearch if true findString represents a regular expression - * @return the position of the specified string, or -1 if the string has not been found - * @since 3.0 - */ - private int findAndSelect(int offset, String findString, boolean forwardSearch, boolean caseSensitive, boolean wholeWord, boolean regExSearch) { - if (fTarget instanceof IFindReplaceTargetExtension3) - return ((IFindReplaceTargetExtension3)fTarget).findAndSelect(offset, findString, forwardSearch, caseSensitive, wholeWord, regExSearch); - return fTarget.findAndSelect(offset, findString, forwardSearch, caseSensitive, wholeWord); - } - /** * Replaces the selection with replaceString. If * regExReplace is true, @@ -948,41 +933,48 @@ Point replaceSelection(String replaceString, boolean regExReplace) { } /** - * Returns whether the specified search string can be found using the given options. + * Returns whether the specified search string can be found using the given + * options. * - * @param findString the string to search for + * @param findString the string to search for * @param forwardSearch the direction of the search * @param caseSensitive should the search be case sensitive - * @param wrapSearch should the search wrap to the start/end if arrived at the end/start - * @param wholeWord does the search string represent a complete word - * @param incremental is this an incremental search - * @param regExSearch if true findString represents a regular expression - * @param beep if true beeps when search does not find a match or needs to wrap - * @return true if the search string can be found using the given options + * @param wrapSearch should the search wrap to the start/end if arrived at + * the end/start + * @param wholeWord does the search string represent a complete word + * @param incremental is this an incremental search + * @param regExSearch if true findString represents a regular + * expression + * @param beep if true beeps when search does not find a + * match or needs to wrap + * @return true if the search string can be found using the given + * options * * @since 3.0 */ - private boolean findNext(String findString, boolean forwardSearch, boolean caseSensitive, boolean wrapSearch, boolean wholeWord, boolean incremental, boolean regExSearch, boolean beep) { + private boolean findNext(String findString, boolean forwardSearch, boolean caseSensitive, boolean wrapSearch, + boolean wholeWord, boolean incremental, boolean regExSearch, boolean beep) { if (fTarget == null) return false; - Point r= null; + Point r = null; if (incremental) - r= fIncrementalBaseLocation; + r = fIncrementalBaseLocation; else - r= fTarget.getSelection(); + r = fTarget.getSelection(); - int findReplacePosition= r.x; + int findReplacePosition = r.x; if (forwardSearch && !fNeedsInitialFindBeforeReplace || !forwardSearch && fNeedsInitialFindBeforeReplace) findReplacePosition += r.y; - fNeedsInitialFindBeforeReplace= false; + fNeedsInitialFindBeforeReplace = false; - int index= findIndex(findString, findReplacePosition, forwardSearch, caseSensitive, wrapSearch, wholeWord, regExSearch, beep); + int index = findIndex(findString, findReplacePosition, forwardSearch, caseSensitive, wrapSearch, wholeWord, + regExSearch, beep); if (index == -1) { - String msg= NLSUtility.format(EditorMessages.FindReplace_Status_noMatchWithValue_label, findString); + String msg = NLSUtility.format(EditorMessages.FindReplace_Status_noMatchWithValue_label, findString); statusMessage(false, EditorMessages.FindReplace_Status_noMatch_label, msg); return false; } @@ -1215,8 +1207,10 @@ private boolean isRegExSearchAvailableAndChecked() { } /** - * Retrieves and returns the option search direction from the appropriate check box. - * @return true if searching forward + * Retrieves and returns the option search direction from the appropriate check + * box. + * + * @return true if searching d */ private boolean isForwardSearch() { if (okToUse(fForwardRadioButton)) { @@ -1584,7 +1578,8 @@ private int replaceAll(String findString, String replaceString, boolean caseSens try { int index= 0; while (index != -1) { - index = findAndSelect(findReplacePosition, findString, true, caseSensitive, wholeWord, regExSearch); + index = fFindReplacer.findAndSelect(findReplacePosition, findString, true, caseSensitive, wholeWord, + regExSearch); if (index != -1) { // substring not contained from current position Point selection= replaceSelection(replaceString, regExSearch); replaceCount++; @@ -1610,7 +1605,7 @@ private int selectAll(String findString, boolean caseSensitive, boolean wholeWor List selectedRegions = new ArrayList<>(); int index = 0; do { - index = findAndSelect(position, findString, true, caseSensitive, wholeWord, regExSearch); + index = fFindReplacer.findAndSelect(position, findString); if (index != -1) { // substring not contained from current position Point selection = fTarget.getSelection(); selectedRegions.add(new Region(selection.x, selection.y)); @@ -1976,4 +1971,10 @@ private void writeHistory(List history, IDialogSettings settings, String settings.put(sectionName, names); } + + private void updateFindReplacerSettings() { + fFindReplacer.setCaseSensitive(isCaseSensitiveSearch()); + fFindReplacer.setWholeWord(isWholeWordSearch()); + fFindReplacer.setRegExSearch(isIncrementalSearch() && isRegExSearchAvailableAndChecked()); + } } diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplacer.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplacer.java new file mode 100644 index 00000000000..19a5ff17c4c --- /dev/null +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/FindReplacer.java @@ -0,0 +1,321 @@ +package org.eclipse.ui.texteditor; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.PatternSyntaxException; + +import org.eclipse.swt.custom.BusyIndicator; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Shell; + +import org.eclipse.jface.text.IFindReplaceTarget; +import org.eclipse.jface.text.IFindReplaceTargetExtension; +import org.eclipse.jface.text.IFindReplaceTargetExtension3; +import org.eclipse.jface.text.IFindReplaceTargetExtension4; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.Region; + +/** + * @since 3.18 + */ +public class FindReplacer { + IFindReplaceTarget target; + Shell activeShell; + + private boolean forwardSearch = true; + private boolean caseSensitive = true; + private boolean wholeWord = false; + private boolean regExSearch = false; + private boolean wrapSearch = true; + private boolean isTargetEditable = true; + + public void setTargetEditable(boolean isTargetEditable) { + this.isTargetEditable = isTargetEditable; + } + + public boolean isTargetEditable() { + return isTargetEditable(); + } + + public boolean isCaseSensitive() { + return caseSensitive; + } + + public void setCaseSensitive(boolean caseSensitive) { + this.caseSensitive = caseSensitive; + } + + public boolean isWholeWord() { + return wholeWord; + } + + public void setWholeWord(boolean wholeWord) { + this.wholeWord = wholeWord; + } + + public boolean isRegExSearch() { + return regExSearch; + } + + public void setRegExSearch(boolean regExSearch) { + this.regExSearch = regExSearch; + } + + public void setForwardSearch(boolean forwardSearch) { + this.forwardSearch = forwardSearch; + } + + public boolean isForwardSearch() { + return forwardSearch; + } + + public void setWrapSearch(boolean wrapSearch) { + this.wrapSearch = wrapSearch; + } + + public boolean isWrapSearch() { + return wrapSearch; + } + + /** + * + * @param target The target for the search and replacement + */ + public FindReplacer(Shell shell, IFindReplaceTarget target) { + activeShell = shell; + this.target = target; + } + + /** + * Searches for a string starting at the given offset and using the specified + * search directives. If a string has been found it is selected and its start + * offset is returned. + * + * @param offset the offset at which searching starts + * @param findString the string which should be found + * @param forwardSearch the direction of the search + * @param caseSensitive true performs a case sensitive search, + * false an insensitive search + * @param wholeWord if true only occurrences are reported in + * which the findString stands as a word by itself + * @param regExSearch if true findString represents a regular + * expression + * @return the position of the specified string, or -1 if the string has not + * been found + * @since 3.0 + */ + public int findAndSelect(int offset, String findString) { + if (target instanceof IFindReplaceTargetExtension3) + return ((IFindReplaceTargetExtension3) target).findAndSelect(offset, findString, forwardSearch, + caseSensitive, wholeWord, regExSearch); + return target.findAndSelect(offset, findString, forwardSearch, caseSensitive, wholeWord); + } + + /** + * Perform "find" from the last position that was found. + * + * @param findString the string which should be found + * @param forwardSearch the direction of the search + * @param caseSensitive true performs a case sensitive search, + * false an insensitive search + * @param wholeWord if true only occurrences are reported in + * which the findString stands as a word by itself + * @param regExSearch if true findString represents a regular + * expression + * @return the position of the specified string, or -1 if the string has not + * been found + * @since 3.0 + */ + public int performSelectNext(String findString) { + int newSearchIndex = computeNewSearchIndex(); + int foundIndex = findAndSelect(newSearchIndex, findString); + + if (wrapSearch && foundIndex == -1) { + findAndSelect(foundIndex, findString); + } + return foundIndex; + } + + public int selectAll(String findString) { + + int replaceCount = 0; + int position = 0; + + List selectedRegions = new ArrayList<>(); + int index = 0; + do { + index = findAndSelect(position, findString); + if (index != -1) { // substring not contained from current position + Point selection = target.getSelection(); + selectedRegions.add(new Region(selection.x, selection.y)); + replaceCount++; + position = selection.x + selection.y; + } + } while (index != -1); + if (target instanceof IFindReplaceTargetExtension4) { + ((IFindReplaceTargetExtension4) target).setSelection(selectedRegions.toArray(IRegion[]::new)); + } + + return replaceCount; + } + + public int performSelectAll(String findString) { + class SelectAllRunnable implements Runnable { + public int numberOfOccurrences; + + @Override + public void run() { + numberOfOccurrences = selectAll(findString); + } + } + + SelectAllRunnable runnable = new SelectAllRunnable(); + BusyIndicator.showWhile(activeShell.getDisplay(), runnable); + return runnable.numberOfOccurrences; + } + + private int computeNewSearchIndex() { + Point IncrementalBaseLocation = target.getSelection(); + int newSearchIndex = IncrementalBaseLocation.x; + if (!forwardSearch) { // MW -> @HeikoKlare. I'm not sure what's going on here. Also, I don't know why + // FindReplaceDialog checks for "fNeedsInitialFindBeforeReplace" + newSearchIndex -= 1; + } else { + newSearchIndex += IncrementalBaseLocation.y; + } + return newSearchIndex; + } + + public void performReplaceAll(String findString, String replaceString) { + replaceAll(findString, replaceString); + } + + /** + * Validates the state of the find/replace target. + * + * @return true if target can be changed, false + * otherwise + * @since 2.1 + */ + private boolean validateTargetState() { + + if (target instanceof IFindReplaceTargetExtension2) { + IFindReplaceTargetExtension2 extension = (IFindReplaceTargetExtension2) target; + if (!extension.validateTargetState()) { +// statusError(EditorMessages.FindReplaceDialog_read_only); + return false; + } + } + return isEditable(); + } + + /** + * Returns whether the target is editable. + * + * @return true if target is editable + */ + private boolean isEditable() { + boolean isEditable = (target == null ? false : target.isEditable()); + return isTargetEditable && isEditable; + } + + /** + * Replaces all occurrences of the user's findString with the replace string. + * Returns the number of replacements that occur. + * + * @param findString the string to search for + * @param replaceString the replacement string + * @param caseSensitive should the search be case sensitive + * @param wholeWord does the search string represent a complete word + * @param regExSearch if true findString represents a regular + * expression + * @return the number of occurrences + * + * @since 3.0 + */ + private int replaceAll(String findString, String replaceString) { + int replaceCount = 0; + int findReplacePosition = 0; + + findReplacePosition = 0; + + if (!validateTargetState()) + return replaceCount; + + if (target instanceof IFindReplaceTargetExtension) + ((IFindReplaceTargetExtension) target).setReplaceAllMode(true); + + try { + int index = 0; + while (index != -1) { + index = findAndSelect(findReplacePosition, findString); + if (index != -1) { // substring not contained from current position + Point selection = replaceSelection(replaceString); + replaceCount++; + findReplacePosition = selection.x + selection.y; + } + } + } finally { + if (target instanceof IFindReplaceTargetExtension) + ((IFindReplaceTargetExtension) target).setReplaceAllMode(false); + } + + return replaceCount; + } + + /** + * Replaces the selection with replaceString. If + * regExReplace is true, replaceString is + * a regex replace pattern which will get expanded if the underlying target + * supports it. Returns the region of the inserted text; note that the returned + * selection covers the expanded pattern in case of regex replace. + * + * @param replaceString the replace string (or a regex pattern) + * @param regExReplace true if replaceString is a + * pattern + * @return the selection after replacing, i.e. the inserted text + * @since 3.0 + */ + Point replaceSelection(String replaceString) { + if (target instanceof IFindReplaceTargetExtension3) + ((IFindReplaceTargetExtension3) target).replaceSelection(replaceString, isRegExSearch()); + else + target.replaceSelection(replaceString); + + return target.getSelection(); + } + + /** + * Replaces the current selection of the target with the user's replace string. + * + * @return true if the operation was successful + */ + private boolean performReplaceSelection(String replaceString) { + if (!validateTargetState()) + return false; + + if (replaceString == null) + replaceString = ""; //$NON-NLS-1$ + + boolean replaced; + try { + replaceSelection(replaceString); + replaced = true; + } catch (PatternSyntaxException ex) { + replaced = false; + } catch (IllegalStateException ex) { + replaced = false; + } + + return replaced; + } + + // TODO: "perform" is a horrible prefix for the method names, I need to change + // them ASAP + public void performReplaceNext(String findString, String replaceString) { + // TODO Auto-generated method stub + performSelectNext(findString); + performReplaceSelection(replaceString); + + } +} diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/InlineFindReplaceComponent.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/InlineFindReplaceComponent.java new file mode 100644 index 00000000000..c5119b76001 --- /dev/null +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/InlineFindReplaceComponent.java @@ -0,0 +1,392 @@ +package org.eclipse.ui.texteditor; + +import java.util.Timer; +import java.util.TimerTask; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.events.TraverseEvent; +import org.eclipse.swt.events.TraverseListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +import org.eclipse.jface.text.IFindReplaceTarget; +import org.eclipse.jface.text.IFindReplaceTargetExtension5; + +import org.eclipse.ui.IWorkbenchPart; + +/** + * The widget for Inline finding and replacing of strings. Will be instantiated + * and injected into the Text editor. + * + * The widget automatically retargets when switching editors. // TODO The widget + * will automatically hook itself up into any editor that implements + * IInlineToolable // TODO The widget uses the same internal logic as the "find + * replace" dialog // TODO The widget will by default perform a "search all" + * + * @since 3.18 + */ +public class InlineFindReplaceComponent { // MW -> @HeikoKlare I'm not sure wether and what I + // should extend from -- maybe Composite? + Timer timer = new Timer(); + private final long waitForUserDoneTypingDelay = 300; + boolean currentlyActive = false; + IWorkbenchPart targetPart; + IFindReplaceTarget target; + FindReplacer findReplacer; + + boolean dialogCreated = false; + Composite container; + Composite searchContainer; + Text searchBar; + Button findAllButton; + Button searchUpButton; + Button searchDownButton; + Button wholeWordSearchButton; + Button caseSensitiveSearchButton; + Button regexSearchButton; + Button openReplaceButton; + Label searchLabel; + + Composite replaceContainer; + Composite replaceOptions; + Text replaceBar; + Button replaceButton; + Button replaceAllButton; + + public InlineFindReplaceComponent(IFindReplaceTarget findReplaceTarget, IWorkbenchPart workbenchPart) { + targetPart = workbenchPart; + target = findReplaceTarget; + findReplacer = new FindReplacer(workbenchPart.getSite().getShell(), target); + } + + public void updateState() { // MW -> @HeikoKlare a lot of these functions reference (StatusTextEditor). + // Eventually, these references will need to be cast into an interface + if (currentlyActive) { + if (targetPart != null) { + createDialog(); + } + } else { + if (dialogCreated) { + hideDialog(); + } + } + } + + public void hideDialog() { + if (openReplaceButton != null) { + if (openReplaceButton.getSelection()) { + hideReplace(); + } + openReplaceButton.dispose(); + } + container.setLayoutData(null); + container.dispose(); + searchBar.dispose(); + searchDownButton.dispose(); + searchUpButton.dispose(); + regexSearchButton.dispose(); + + dialogCreated = false; + if (targetPart instanceof IFindReplaceTargetExtension5 tp) { + tp.endInlineSession(); + tp.updateLayout(); + } + } + + public void hideReplace() { + setNormalTablist(); + replaceContainer.setLayout(null); + replaceContainer.dispose(); + replaceOptions.dispose(); + replaceBar.dispose(); + ((IFindReplaceTargetExtension5) targetPart).updateLayout(); + } + + private void setNormalTablist() { + searchContainer.setTabList(new Control[] { searchBar }); + } + + private void setReplaceTablist() { + replaceContainer.setTabList(new Control[] { replaceBar }); + } + + public void createDialog() { // MW -> @HeikoKlare we need to rethink how the dialog is built if we + // want to generalize this in the future + // TODO clean up this mess + if (targetPart instanceof IFindReplaceTargetExtension5 tp) + container = tp.beginInlineSession(); + container.setLayout(new GridLayout(1, false)); + GridData findContainerGD = new GridData(); + findContainerGD.grabExcessHorizontalSpace = true; + findContainerGD.horizontalAlignment = GridData.FILL; + findContainerGD.verticalAlignment = GridData.FILL; + container.setLayoutData(findContainerGD); + + searchContainer = new Composite(container, SWT.BORDER); // The border looks funny. TODO + GridData searchContainerGD = new GridData(); + searchContainerGD.grabExcessHorizontalSpace = true; + searchContainerGD.horizontalAlignment = GridData.FILL; + searchContainerGD.verticalAlignment = GridData.FILL; + searchContainer.setLayoutData(searchContainerGD); + searchContainer.setLayout(new GridLayout(8, false)); + searchBar = new Text(searchContainer, SWT.SINGLE); + searchLabel = new Label(searchContainer, SWT.NONE); + searchLabel.setText(" "); + GridData searchBarGridData = new GridData(); + searchBarGridData.grabExcessHorizontalSpace = true; + searchBarGridData.grabExcessVerticalSpace = true; + searchBarGridData.horizontalAlignment = GridData.FILL; + searchBarGridData.verticalAlignment = GridData.CENTER; + searchBar.setLayoutData(searchBarGridData); + searchBar.forceFocus(); + searchBar.selectAll(); + searchUpButton = new Button(searchContainer, SWT.TOGGLE); + searchUpButton.setText(" ⬆️ "); //$NON-NLS-1$ + searchUpButton.setToolTipText("Search backward"); + searchUpButton.addSelectionListener(new SelectionListener() { + @Override + public void widgetSelected(SelectionEvent e) { + searchUpButton.setSelection(true); + searchDownButton.setSelection(false); + findReplacer.setForwardSearch(false); + search(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + // TODO Auto-generated method stub + + } + }); + searchDownButton = new Button(searchContainer, SWT.TOGGLE); + searchDownButton.setSelection(true); // by default, search down + searchDownButton.setText(" ⬇️ "); //$NON-NLS-1$ + searchDownButton.setToolTipText("Search forward"); + searchDownButton.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + searchUpButton.setSelection(false); + searchDownButton.setSelection(true); + findReplacer.setForwardSearch(true); + search(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + // TODO Auto-generated method stub + + } + }); + wholeWordSearchButton = new Button(searchContainer, SWT.TOGGLE); + wholeWordSearchButton.setText(" ♊️ "); + wholeWordSearchButton.setToolTipText("Only find in whole words"); + wholeWordSearchButton.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + findReplacer.setWholeWord(wholeWordSearchButton.getSelection()); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + // TODO Auto-generated method stub + + } + }); + caseSensitiveSearchButton = new Button(searchContainer, SWT.TOGGLE); + caseSensitiveSearchButton.setText(" 🔠 "); + caseSensitiveSearchButton.setToolTipText("Match case"); + caseSensitiveSearchButton.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + findReplacer.setCaseSensitive(caseSensitiveSearchButton.getSelection()); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + // TODO Auto-generated method stub + + } + }); + regexSearchButton = new Button(searchContainer, SWT.TOGGLE); + regexSearchButton.setText(" ⚙️ "); //$NON-NLS-1$ + regexSearchButton.setToolTipText("Search for a regular expression"); //$NON-NLS-1$ + regexSearchButton.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + findReplacer.setRegExSearch(regexSearchButton.getSelection()); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + // TODO Auto-generated method stub + } + }); + + if (target.isEditable()) { + openReplaceButton = new Button(searchContainer, SWT.TOGGLE); + openReplaceButton.setText(" 🔄 "); //$NON-NLS-1$ + openReplaceButton.addSelectionListener(new SelectionListener() { + @Override + public void widgetSelected(SelectionEvent e) { + if (openReplaceButton.getSelection()) { + createReplaceDialog(); + } else { + hideReplace(); + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + // TODO Auto-generated method stub + + } + }); + } + + // Problem: shift+8 ("(") will not be typed into the search Bar since it is + // already a bound key. We need to override this behaviour FIXME + // Problem also generalizes to other keybinds: Ctrl + backspace, ... + // We need to convince the editor that we aren't writing to it. + searchBar.addTraverseListener(new TraverseListener() { + @Override + public void keyTraversed(final TraverseEvent event) { + if (event.detail == SWT.TRAVERSE_RETURN) { + search(); + } + } + }); + searchBar.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + timer.cancel(); + timer = new Timer(); + timer.schedule(new TimerTask() { + @Override + public void run() { + Display.getDefault().asyncExec(new Runnable() { // https://wiki.eclipse.org/FAQ_Why_do_I_get_an_invalid_thread_access_exception%3F + @Override + public void run() { + selectAll(); + } + }); + } + + }, waitForUserDoneTypingDelay); + } + + }); + searchBar.setMessage(" 🔎 Find"); //$NON-NLS-1$ + + setNormalTablist(); + container.layout(); + ((IFindReplaceTargetExtension5) targetPart).updateLayout(); + dialogCreated = true; + + } + + public void createReplaceDialog() { + Composite parent = container; + replaceContainer = new Composite(parent, SWT.BORDER); + replaceContainer.setLayout(new GridLayout(3, false)); + GridData replaceContainerLayoutData = new GridData(); + replaceContainerLayoutData.grabExcessHorizontalSpace = true; + replaceContainerLayoutData.horizontalAlignment = SWT.FILL; + replaceContainer.setLayoutData(replaceContainerLayoutData); + + replaceBar = new Text(replaceContainer, SWT.SINGLE); + GridData replaceBarData = new GridData(); + replaceBarData.grabExcessHorizontalSpace = true; + replaceBarData.horizontalAlignment = SWT.FILL; + replaceBar.setLayoutData(replaceBarData); + replaceBar.setMessage(" 🔄 Replace"); //$NON-NLS-1$ + + replaceOptions = new Composite(replaceContainer, SWT.NONE); + replaceOptions.setLayout(new GridLayout(3, false)); + replaceButton = new Button(replaceOptions, SWT.PUSH); + replaceButton.setText(" 🔂 "); //$NON-NLS-1$ + replaceButton.setToolTipText("Replace"); + replaceButton.addSelectionListener(new SelectionListener() { + @Override + public void widgetSelected(SelectionEvent e) { + replaceNext(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + replaceAllButton = new Button(replaceOptions, SWT.PUSH); + replaceAllButton.setText(" 🔁 "); //$NON-NLS-1$ + replaceAllButton.setToolTipText("Replace All"); + replaceAllButton.addSelectionListener(new SelectionListener() { + @Override + public void widgetSelected(SelectionEvent e) { + replaceAll(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + // TODO Auto-generated method stub + + } + }); + replaceBar.forceFocus(); + + setReplaceTablist(); + ((IFindReplaceTargetExtension5) targetPart).updateLayout(); + } + + public void toggleActive() { + currentlyActive = !currentlyActive; + updateState(); + } + + private String getFindString() { + return searchBar.getText(); + } + + private String getReplaceString() { + return replaceBar.getText(); + } + + private int search() { + return findReplacer.performSelectNext(getFindString()); + } + + private void selectAll() { // TODO: we want the editor to go back to the current scroll state after + // "selecting all" + int occurrences = findReplacer.performSelectAll(getFindString()); + // XXX We need to consider how the display of occurrences behaves in languages + // that are not written left-to-right. This leads to a frequent resize of + // the write box which looks like the beginning of the text moves around a lot + // in a language written right-to-left + if (getFindString() != "" && getFindString() != null) { + searchLabel.setText(Integer.toString(occurrences)); // $NON-NLS-1$ + } else { + searchLabel.setText(""); + } + searchContainer.layout(); + } + + private void replaceNext() { // where does replaceNext know the direction from? + findReplacer.performReplaceNext(getFindString(), getReplaceString()); + } + + private void replaceAll() { + findReplacer.performReplaceAll(getFindString(), getReplaceString()); + } +} diff --git a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/StatusTextEditor.java b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/StatusTextEditor.java index f7a24ddb28f..9912bca54b5 100644 --- a/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/StatusTextEditor.java +++ b/bundles/org.eclipse.ui.workbench.texteditor/src/org/eclipse/ui/texteditor/StatusTextEditor.java @@ -14,10 +14,12 @@ package org.eclipse.ui.texteditor; - import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StackLayout; +import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.FillLayout; +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.Shell; @@ -25,22 +27,29 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; +import org.eclipse.jface.text.IFindReplaceTarget; +import org.eclipse.jface.text.IFindReplaceTargetExtension5; + import org.eclipse.ui.IEditorInput; import org.eclipse.ui.PlatformUI; - /** * Capable of handling input elements that have an associated status with them. + * * @since 2.0 */ -public class StatusTextEditor extends AbstractTextEditor { +public class StatusTextEditor extends AbstractTextEditor implements IFindReplaceTarget, IFindReplaceTargetExtension5 { /** The root composite of this editor */ private Composite fParent; /** The layout used to manage the regular and the status page */ private StackLayout fStackLayout; /** The root composite for the regular page */ - private Composite fDefaultComposite; + private Composite fPageComposite; + /** Composite for the Editor */ + private Composite fEditorComposite; + /** Composite for the Inline Toolbar */ + private Composite fSearchReplaceComposite; /** The status page */ private Control fStatusControl; /** {@link #setFocus()} is still running */ @@ -49,26 +58,62 @@ public class StatusTextEditor extends AbstractTextEditor { // No .options for plugin yet private static final boolean DEBUG = false; + /** + * @deprecated Needs to be reconsidered + * @return the inline-toolbar composite + * @since 3.18 + */ + @Deprecated + public Composite getInlineToolbarParent() { // MW -> @HeikoKlare: Bad style, I would prefer a solution where this + // function takes in an abstraction of - for example - IInlineToolbar + // and calls + // createControls(fInlineToolbar) on it. We need to define how + // generalized this implementation should become. Returning the Full + // inline toolbar composite is not helping in keeping things abstract. + // We also should think about wether we want StatusTextEditor to perform + // this task or wether we want to outsource this into a superclass + return fSearchReplaceComposite; + } + /* - * @see org.eclipse.ui.texteditor.AbstractTextEditor.createPartControl(Composite) + * @see + * org.eclipse.ui.texteditor.AbstractTextEditor.createPartControl(Composite) */ @Override public void createPartControl(Composite parent) { - fParent= new Composite(parent, SWT.NONE); - fStackLayout= new StackLayout(); + // TODO: Somewhere, I am creating ugly spaces at the border of the Text Editor. + // I am not sure how to remove them. Investigation required! + fParent = new Composite(parent, SWT.NONE); + fStackLayout = new StackLayout(); fParent.setLayout(fStackLayout); - fDefaultComposite= new Composite(fParent, SWT.NONE); - fDefaultComposite.setLayout(new FillLayout()); - super.createPartControl(fDefaultComposite); + fPageComposite = new Composite(fParent, SWT.NONE); + GridLayout fPageCompositeLayout = new GridLayout(1, true); + fPageCompositeLayout.marginBottom = 0; + fPageCompositeLayout.verticalSpacing = 0; + fPageCompositeLayout.horizontalSpacing = 0; + fPageComposite.setLayout(fPageCompositeLayout); + + fEditorComposite = new Composite(fPageComposite, SWT.NONE); + FillLayout editorCompositeLayout = new FillLayout(); + editorCompositeLayout.marginHeight = 0; + editorCompositeLayout.marginWidth = 0; + fEditorComposite.setLayout(new FillLayout()); + GridData pageCompositeLayoutData = new GridData(); + pageCompositeLayoutData.grabExcessHorizontalSpace = true; + pageCompositeLayoutData.grabExcessVerticalSpace = true; + pageCompositeLayoutData.horizontalAlignment = GridData.FILL; + pageCompositeLayoutData.verticalAlignment = GridData.FILL; + fEditorComposite.setLayoutData(pageCompositeLayoutData); + super.createPartControl(fEditorComposite); updatePartControl(getEditorInput()); } /** - * Checks if the status of the given input is OK. If not the - * status control is shown rather than the default control. + * Checks if the status of the given input is OK. If not the status control is + * shown rather than the default control. * * @param input the input whose status is checked */ @@ -80,34 +125,34 @@ public void updatePartControl(IEditorInput input) { trace(where, "START", fStatusControl); //$NON-NLS-1$ } - boolean restoreFocus= false; + boolean restoreFocus = false; if (fStatusControl != null) { if (!fStatusControl.isDisposed()) { - restoreFocus= containsFocus(fStatusControl); + restoreFocus = containsFocus(fStatusControl); } fStatusControl.dispose(); trace(where, "status control disposed", fStatusControl); //$NON-NLS-1$ - fStatusControl= null; + fStatusControl = null; } - Control front= null; + Control front = null; if (fParent != null && input != null) { if (getDocumentProvider() instanceof IDocumentProviderExtension) { - IDocumentProviderExtension extension= (IDocumentProviderExtension) getDocumentProvider(); - IStatus status= extension.getStatus(input); + IDocumentProviderExtension extension = (IDocumentProviderExtension) getDocumentProvider(); + IStatus status = extension.getStatus(input); if (!isErrorStatus(status)) { - front= fDefaultComposite; + front = fPageComposite; } else { - fStatusControl= createStatusControl(fParent, status); + fStatusControl = createStatusControl(fParent, status); trace(where, "status control created", fStatusControl); //$NON-NLS-1$ - front= fStatusControl; + front = fStatusControl; } } } if (fStackLayout.topControl != front) { - fStackLayout.topControl= front; + fStackLayout.topControl = front; if (front != null) { front.requestLayout(); } @@ -118,14 +163,15 @@ public void updatePartControl(IEditorInput input) { fParent.setFocus(); } trace(where, "END", fStatusControl); //$NON-NLS-1$ + fPageComposite.layout(); } private boolean containsFocus(Control control) { - Control focusControl= control.getDisplay().getFocusControl(); + Control focusControl = control.getDisplay().getFocusControl(); if (focusControl != null) { - focusControl= focusControl.getParent(); + focusControl = focusControl.getParent(); while (focusControl != fParent && focusControl != null && !(focusControl instanceof Shell)) { - focusControl= focusControl.getParent(); + focusControl = focusControl.getParent(); } } return focusControl == fParent; @@ -142,8 +188,10 @@ public void setFocus() { setFocusIsRunning = true; if (fStatusControl != null && !fStatusControl.isDisposed()) { - /* even if the control does not really take focus, we still have to set it - * to fulfill the contract and to make e.g. Ctrl+PageUp/Down work. */ + /* + * even if the control does not really take focus, we still have to set it to + * fulfill the contract and to make e.g. Ctrl+PageUp/Down work. + */ fStatusControl.setFocus(); } else { super.setFocus(); @@ -160,8 +208,8 @@ public boolean validateEditorInputState() { return false; if (getDocumentProvider() instanceof IDocumentProviderExtension) { - IDocumentProviderExtension extension= (IDocumentProviderExtension)getDocumentProvider(); - IStatus status= extension.getStatus(getEditorInput()); + IDocumentProviderExtension extension = (IDocumentProviderExtension) getDocumentProvider(); + IStatus status = extension.getStatus(getEditorInput()); return !isErrorStatus(status) && status.getSeverity() != IStatus.CANCEL; } @@ -172,7 +220,8 @@ public boolean validateEditorInputState() { * Returns whether the given status indicates an error. Subclasses may override. * * @param status the status to be checked - * @return true if the status indicates an error, false otherwise\ + * @return true if the status indicates an error, + * false otherwise\ * @since 3.0 */ protected boolean isErrorStatus(IStatus status) { @@ -180,8 +229,8 @@ protected boolean isErrorStatus(IStatus status) { } /** - * Creates the status control for the given status. - * May be overridden by subclasses. + * Creates the status control for the given status. May be overridden by + * subclasses. * * @param parent the parent control * @param status the status @@ -202,7 +251,7 @@ protected Control createStatusControl(Composite parent, IStatus status) { */ @Deprecated private Control createInfoForm(Composite parent, IStatus status) { - InfoForm infoForm= new InfoForm(parent); + InfoForm infoForm = new InfoForm(parent); infoForm.setHeaderText(getStatusHeader(status)); infoForm.setBannerText(getStatusBanner(status)); infoForm.setInfo(getStatusMessage(status)); @@ -241,12 +290,12 @@ protected String getStatusMessage(IStatus status) { @Override protected void updateStatusField(String category) { - IDocumentProvider provider= getDocumentProvider(); + IDocumentProvider provider = getDocumentProvider(); if (provider instanceof IDocumentProviderExtension) { - IDocumentProviderExtension extension= (IDocumentProviderExtension) provider; - IStatus status= extension.getStatus(getEditorInput()); + IDocumentProviderExtension extension = (IDocumentProviderExtension) provider; + IStatus status = extension.getStatus(getEditorInput()); if (isErrorStatus(status)) { - IStatusField field= getStatusField(category); + IStatusField field = getStatusField(category); if (field != null) { field.setText(fErrorLabel); return; @@ -315,4 +364,67 @@ private static void trace(String where, String what, Control o) { } System.out.println(where + " |" + id + "| " + what); //$NON-NLS-1$//$NON-NLS-2$ } + + /** + * @since 3.17 + */ + @Override + public Composite beginInlineSession() { + fSearchReplaceComposite = new Composite(fPageComposite, SWT.NONE); + fSearchReplaceComposite.setLayout(new GridLayout(1, false)); + GridData srGridData = new GridData(); + srGridData.horizontalAlignment = GridData.FILL; + srGridData.verticalAlignment = GridData.FILL; + fSearchReplaceComposite.setLayoutData(srGridData); + + return fSearchReplaceComposite; + } + + /** + * @since 3.17 + */ + @Override + public void updateLayout() { + updatePartControl(); + } + + /** + * @since 3.17 + */ + @Override + public void endInlineSession() { + fSearchReplaceComposite.dispose(); + fSearchReplaceComposite = null; + } + + @Override + public boolean canPerformFind() { + // TODO Auto-generated method stub + return true; + } + + @Override + public int findAndSelect(int widgetOffset, String findString, boolean searchForward, boolean caseSensitive, + boolean wholeWord) { + // TODO Auto-generated method stub + return 0; + } + + @Override + public Point getSelection() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getSelectionText() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void replaceSelection(String text) { + // TODO Auto-generated method stub + + } } diff --git a/examples/org.eclipse.ui.examples.adapterservice/Adapter Snippet.launch b/examples/org.eclipse.ui.examples.adapterservice/Adapter Snippet.launch index 8726b519851..c81f7d917d2 100644 --- a/examples/org.eclipse.ui.examples.adapterservice/Adapter Snippet.launch +++ b/examples/org.eclipse.ui.examples.adapterservice/Adapter Snippet.launch @@ -1,34 +1,104 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/org.eclipse.jface.tests/icons/editor.gif b/tests/org.eclipse.jface.tests/icons/editor.gif index 6c5facf55d6..9bd92bfce97 100644 --- a/tests/org.eclipse.jface.tests/icons/editor.gif +++ b/tests/org.eclipse.jface.tests/icons/editor.gif @@ -1 +1 @@ -GIF89a +GIF89a diff --git a/tests/org.eclipse.jface.tests/icons/imagetests/editor.gif b/tests/org.eclipse.jface.tests/icons/imagetests/editor.gif index 6c5facf55d6..9bd92bfce97 100644 --- a/tests/org.eclipse.jface.tests/icons/imagetests/editor.gif +++ b/tests/org.eclipse.jface.tests/icons/imagetests/editor.gif @@ -1 +1 @@ -GIF89a +GIF89a diff --git a/tests/org.eclipse.ui.tests.performance/icons/editor.gif b/tests/org.eclipse.ui.tests.performance/icons/editor.gif index 6c5facf55d6..9bd92bfce97 100644 --- a/tests/org.eclipse.ui.tests.performance/icons/editor.gif +++ b/tests/org.eclipse.ui.tests.performance/icons/editor.gif @@ -1 +1 @@ -GIF89a +GIF89a diff --git a/tests/org.eclipse.ui.tests.performance/icons/imagetests/editor.gif b/tests/org.eclipse.ui.tests.performance/icons/imagetests/editor.gif index 6c5facf55d6..9bd92bfce97 100644 --- a/tests/org.eclipse.ui.tests.performance/icons/imagetests/editor.gif +++ b/tests/org.eclipse.ui.tests.performance/icons/imagetests/editor.gif @@ -1 +1 @@ -GIF89a +GIF89a diff --git a/tests/org.eclipse.ui.tests/icons/editor.gif b/tests/org.eclipse.ui.tests/icons/editor.gif index 6c5facf55d6..9bd92bfce97 100644 --- a/tests/org.eclipse.ui.tests/icons/editor.gif +++ b/tests/org.eclipse.ui.tests/icons/editor.gif @@ -1 +1 @@ -GIF89a +GIF89a diff --git a/tests/org.eclipse.ui.tests/icons/imagetests/editor.gif b/tests/org.eclipse.ui.tests/icons/imagetests/editor.gif index 6c5facf55d6..9bd92bfce97 100644 --- a/tests/org.eclipse.ui.tests/icons/imagetests/editor.gif +++ b/tests/org.eclipse.ui.tests/icons/imagetests/editor.gif @@ -1 +1 @@ -GIF89a +GIF89a