Eclipseplugins
GitGrepSearchResultPage.java
1 package com.proalpha.pds.gitutils.search;
2 
3 import java.io.File;
4 import java.io.IOException;
5 import java.nio.file.Files;
6 import java.util.HashSet;
7 import java.util.Set;
8 
9 import org.eclipse.core.filesystem.EFS;
10 import org.eclipse.core.filesystem.IFileStore;
11 import org.eclipse.core.runtime.IProgressMonitor;
12 import org.eclipse.core.runtime.IStatus;
13 import org.eclipse.core.runtime.Status;
14 import org.eclipse.jface.text.BadLocationException;
15 import org.eclipse.jface.text.IDocument;
16 import org.eclipse.jface.viewers.CellLabelProvider;
17 import org.eclipse.jface.viewers.DoubleClickEvent;
18 import org.eclipse.jface.viewers.IDoubleClickListener;
19 import org.eclipse.jface.viewers.ISelection;
20 import org.eclipse.jface.viewers.ISelectionChangedListener;
21 import org.eclipse.jface.viewers.IStructuredContentProvider;
22 import org.eclipse.jface.viewers.IStructuredSelection;
23 import org.eclipse.jface.viewers.SelectionChangedEvent;
24 import org.eclipse.jface.viewers.TableViewer;
25 import org.eclipse.jface.viewers.TableViewerColumn;
26 import org.eclipse.jface.viewers.Viewer;
27 import org.eclipse.jface.viewers.ViewerCell;
28 import org.eclipse.jface.viewers.ViewerComparator;
29 import org.eclipse.search.ui.IQueryListener;
30 import org.eclipse.search.ui.ISearchQuery;
31 import org.eclipse.search.ui.ISearchResult;
32 import org.eclipse.search.ui.ISearchResultListener;
33 import org.eclipse.search.ui.ISearchResultPage;
34 import org.eclipse.search.ui.ISearchResultViewPart;
35 import org.eclipse.search.ui.NewSearchUI;
36 import org.eclipse.search.ui.SearchResultEvent;
37 import org.eclipse.search.ui.text.AbstractTextSearchResult;
38 import org.eclipse.search.ui.text.FilterUpdateEvent;
39 import org.eclipse.search.ui.text.Match;
40 import org.eclipse.search.ui.text.MatchEvent;
41 import org.eclipse.search.ui.text.RemoveAllEvent;
42 import org.eclipse.swt.SWT;
43 import org.eclipse.swt.custom.SashForm;
44 import org.eclipse.swt.custom.StyledText;
45 import org.eclipse.swt.graphics.Font;
46 import org.eclipse.swt.graphics.FontData;
47 import org.eclipse.swt.layout.GridData;
48 import org.eclipse.swt.layout.GridLayout;
49 import org.eclipse.swt.widgets.Composite;
50 import org.eclipse.swt.widgets.Control;
51 import org.eclipse.swt.widgets.Display;
52 import org.eclipse.swt.widgets.Table;
53 import org.eclipse.swt.widgets.TableItem;
54 import org.eclipse.ui.IEditorPart;
55 import org.eclipse.ui.IMemento;
56 import org.eclipse.ui.IWorkbenchPage;
57 import org.eclipse.ui.PartInitException;
58 import org.eclipse.ui.PlatformUI;
59 import org.eclipse.ui.ide.IDE;
60 import org.eclipse.ui.part.Page;
61 import org.eclipse.ui.part.PageBook;
62 import org.eclipse.ui.progress.UIJob;
63 import org.eclipse.ui.texteditor.IDocumentProvider;
64 import org.eclipse.ui.texteditor.ITextEditor;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67 
68 public class GitGrepSearchResultPage extends Page implements ISearchResultPage {
69 
70  private final Logger logger = LoggerFactory.getLogger(GitGrepSearchResultPage.class);
71 
72  private Control fBusyLabel;
73  private GitGrepSearchResult fInput;
74  private IQueryListener fQueryListener;
75  private ISearchResultListener fListener;
76  private ISearchResultViewPart fViewPart;
77  private PageBook fPagebook;
78  private SashForm sashForm;
79  private Set<Object> fBatchedUpdates;
80  private String fId;
81  private StyledText textArea;
82  private TableViewer fViewer;
83  private boolean fBatchedClearAll;
84  private boolean fIsBusyShown;
85  private volatile boolean fIsUIUpdateScheduled = false;
86  private volatile boolean fScheduleEnsureSelection = false;
87 
88  public GitGrepSearchResultPage() {
89  fBatchedUpdates = new HashSet<>();
90  fBatchedClearAll = false;
91 
92  fListener = new ISearchResultListener() {
93  public void searchResultChanged(SearchResultEvent e) {
94  handleSearchResultChanged(e);
95  }
96  };
97  }
98 
99  public void setID(String id) {
100  fId = id;
101  }
102 
103  public String getID() {
104  return fId;
105  }
106 
107  public String getLabel() {
108  AbstractTextSearchResult result = fInput;
109  if (result == null) {
110  return "";
111  }
112  return result.getLabel();
113  }
114 
115  protected void configureTableViewer(TableViewer viewer) {
116 
117  customizeTable(viewer);
118  viewer.setContentProvider(new GitGrepContentProvider());
119  viewer.setLabelProvider(new GitGrepLabelProvider());
120  viewer.setComparator(new ViewerComparator() {
121 
122  @Override
123  public int compare(Viewer viewer, Object e1, Object e2) {
126 
127  return el1.compareTo(el2);
128  }
129 
130  @Override
131  public void sort(Viewer viewer, Object[] elements) {
132 
133  super.sort(viewer, elements);
134  }
135  });
136  }
137 
138  public void createControl(Composite parent) {
139  GridLayout gridLayout = new GridLayout();
140  gridLayout.numColumns = 2;
141 
142  fQueryListener = createQueryListener();
143 
144  fPagebook = new PageBook(parent, SWT.NULL);
145  fPagebook.setLayoutData(new GridData(GridData.FILL_BOTH));
146  fBusyLabel = createBusyControl();
147 
148  sashForm = new SashForm(fPagebook, SWT.HORIZONTAL);
149  sashForm.setLayoutData(new GridData(GridData.FILL_BOTH));
150  sashForm.setLayout(gridLayout);
151 
152  createViewer(sashForm);
153  createTextArea(sashForm);
154 
155  showBusyLabel(fIsBusyShown);
156  NewSearchUI.addQueryListener(fQueryListener);
157  }
158 
159  private void scheduleUIUpdate() {
160  if (!fIsUIUpdateScheduled) {
161  fIsUIUpdateScheduled = true;
162  new UpdateUIJob().schedule();
163  }
164  }
165 
166  private IQueryListener createQueryListener() {
167  return new IQueryListener() {
168  public void queryAdded(ISearchQuery query) {
169  // We don't need this here
170  }
171 
172  public void queryRemoved(ISearchQuery query) {
173  // We don't need this here
174  }
175 
176  public void queryStarting(final ISearchQuery query) {
177  final Runnable runnable1 = new Runnable() {
178  public void run() {
179  updateBusyLabel();
180  AbstractTextSearchResult result = fInput;
181 
182  if (result == null || !result.getQuery().equals(query)) {
183  return;
184  }
185  scheduleUIUpdate();
186  }
187  };
188  asyncExec(runnable1);
189  }
190 
191  public void queryFinished(final ISearchQuery query) {
192  postEnsureSelection();
193  }
194  };
195  }
196 
197  protected void postEnsureSelection() {
198  fScheduleEnsureSelection = true;
199  scheduleUIUpdate();
200  }
201 
202  private void createViewer(Composite parent) {
203  GridData gridData = new GridData();
204  gridData.horizontalAlignment = GridData.FILL;
205  gridData.grabExcessHorizontalSpace = true;
206  gridData.grabExcessVerticalSpace = true;
207  gridData.verticalAlignment = GridData.FILL;
208 
209  TableViewer viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
210  fViewer = viewer;
211  fViewer.getTable().setLayoutData(gridData);
212  configureTableViewer(viewer);
213 
214  getSite().setSelectionProvider(fViewer);
215 
216  fViewer.addSelectionChangedListener(new ISelectionChangedListener() {
217  public void selectionChanged(SelectionChangedEvent event) {
218 
219  final GitGrepSearchResultElement selectedElement = getSelectedElement();
220  fillTextArea(selectedElement);
221  }
222 
223  private void fillTextArea(GitGrepSearchResultElement selectedElement) {
224  if ((selectedElement.getBlock() == null) || (selectedElement.getLineNr() == null)) {
225  return;
226  }
227 
228  File fileToOpen = new File(selectedElement.getAbsolutePath());
229 
230  if (fileToOpen.exists() && fileToOpen.isFile()) {
231  byte[] fileContent = null;
232  try {
233  fileContent = Files.readAllBytes(fileToOpen.toPath());
234  } catch (IOException e) {
235  logger.debug("file content could not be read because ", e);
236  }
237 
238  textArea.setText(new String(fileContent));
239  textArea.setTopIndex(Integer.parseInt(selectedElement.getLineNr()) - 1);
240  textArea.setEditable(false);
241  } else {
242  // Do something if the file does not exist
243  logger.error("The file {} doesn't exist.", fileToOpen);
244  }
245  }
246 
247  private GitGrepSearchResultElement getSelectedElement() {
248  GitGrepSearchResultElement selectedElement;
249  IStructuredSelection selection = (IStructuredSelection) fViewer.getSelection();
250 
251  if (selection.isEmpty()) {
252  selectedElement = new GitGrepSearchResultElement();
253  } else {
254  selectedElement = (GitGrepSearchResultElement) selection.getFirstElement();
255  }
256  return selectedElement;
257  }
258  });
259 
260  fViewer.addDoubleClickListener(new IDoubleClickListener() {
261 
262  public void doubleClick(DoubleClickEvent event) {
263 
264  fViewer = (TableViewer) event.getSource();
265  IStructuredSelection el = (IStructuredSelection) fViewer.getSelection();
266  GitGrepSearchResultElement elem = (GitGrepSearchResultElement) el.getFirstElement();
267 
268  File fileToOpen = new File(elem.getAbsolutePath());
269 
270  if (fileToOpen.exists() && fileToOpen.isFile()) {
271  IFileStore fileStore = EFS.getLocalFileSystem().getStore(fileToOpen.toURI());
272  IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
273 
274  try {
275  IEditorPart editor = IDE.openEditorOnFileStore(page, fileStore);
276 
277  if (editor instanceof ITextEditor) {
278  IDocumentProvider provider = ((ITextEditor) editor).getDocumentProvider();
279  IDocument document = provider.getDocument(editor.getEditorInput());
280 
281  int start = 0;
282  try {
283  start = document.getLineOffset(Integer.parseInt(elem.getLineNr()) - 1);
284  } catch (NumberFormatException | BadLocationException e) {
285  logger.debug("line number could not be parsed to int because ", e);
286  }
287 
288  ((ITextEditor) editor).selectAndReveal(start, 0);
289  }
290 
291  } catch (PartInitException e) {
292  // Put your exception handler here if you wish to
293  logger.error(e.getMessage(), e);
294  }
295  } else {
296  logger.error("The file {} doesn't exist.", fileToOpen);
297  }
298  }
299  });
300 
301  fViewPart.updateLabel();
302  }
303 
304  private void createTextArea(Composite parent) {
305  GridData gridData = new GridData();
306  gridData.grabExcessHorizontalSpace = true;
307  gridData.horizontalAlignment = GridData.FILL;
308  gridData.verticalAlignment = GridData.FILL;
309  gridData.grabExcessVerticalSpace = true;
310  textArea = new StyledText(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
311  textArea.setLayoutData(gridData);
312  FontData defaultFont = new FontData("Consolas", 10, SWT.NORMAL);
313  Font font = new Font(parent.getDisplay(), defaultFont);
314 
315  textArea.setFont(font);
316  }
317 
318  private void customizeTable(TableViewer viewer) {
319 
320  TableViewerColumn columnObject = new TableViewerColumn(viewer, SWT.NONE);
321  TableViewerColumn columnContent = new TableViewerColumn(viewer, SWT.NONE);
322  TableViewerColumn columnLine = new TableViewerColumn(viewer, SWT.NONE);
323  columnObject.getColumn().setText("Objectname");
324  columnObject.getColumn().setResizable(true);
325  columnObject.getColumn().setWidth(110);
326  columnContent.getColumn().setText("Line");
327  columnContent.getColumn().setResizable(true);
328  columnContent.getColumn().setWidth(50);
329  columnLine.getColumn().setText("Content");
330  columnLine.getColumn().setResizable(true);
331  columnLine.getColumn().setWidth(700);
332  viewer.getTable().setHeaderVisible(true);
333  viewer.getTable().setLinesVisible(true);
334  FontData defaultFont = new FontData("Consolas", 10, SWT.NORMAL);
335  Font font = new Font(viewer.getTable().getDisplay(), defaultFont);
336  viewer.getTable().setFont(font);
337  }
338 
339  private Control createBusyControl() {
340  Table busyLabel = new Table(fPagebook, SWT.NONE);
341  TableItem item = new TableItem(busyLabel, SWT.NONE);
342  item.setText("searching....");
343  busyLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
344  return busyLabel;
345  }
346 
347  private void updateBusyLabel() {
348  AbstractTextSearchResult result = fInput;
349  boolean shouldShowBusy = result != null && NewSearchUI.isQueryRunning(result.getQuery())
350  && result.getMatchCount() == 0;
351  if (shouldShowBusy == fIsBusyShown) {
352  return;
353  }
354  fIsBusyShown = shouldShowBusy;
355  showBusyLabel(fIsBusyShown);
356  }
357 
358  private void showBusyLabel(boolean shouldShowBusy) {
359  if (shouldShowBusy) {
360  fPagebook.showPage(fBusyLabel);
361  } else {
362  fPagebook.showPage(sashForm);
363  }
364  }
365 
366  private void disposeViewer() {
367  fViewer.getControl().dispose();
368  fViewer = null;
369  }
370 
371  public void dispose() {
372  super.dispose();
373  disposeViewer();
374  NewSearchUI.removeQueryListener(fQueryListener);
375  }
376 
377  public void setFocus() {
378  Control control = fViewer.getControl();
379  if (control != null && !control.isDisposed()) {
380  control.setFocus();
381  }
382  }
383 
384  public Control getControl() {
385  return fPagebook;
386  }
387 
388  public void setInput(ISearchResult newSearch, Object viewState) {
389  if (newSearch instanceof GitGrepSearchResult) {
390  textArea.setText("");
391  GitGrepSearchResult oldSearch = fInput;
392  if (oldSearch != null) {
393  fViewer.setInput(null);
394  oldSearch.removeListener(fListener);
395  }
396  fInput = (GitGrepSearchResult) newSearch;
397 
398  fInput.addListener(fListener);
399  fViewer.setInput(fInput);
400  if (viewState instanceof ISelection) {
401  fViewer.setSelection((ISelection) viewState, true);
402  }
403 
404  updateBusyLabel();
405  scheduleUIUpdate();
406  }
407  }
408 
409  public Object getUIState() {
410  return fViewer.getSelection();
411  }
412 
413  public void setViewPart(ISearchResultViewPart part) {
414  fViewPart = part;
415  }
416 
417  protected ISearchResultViewPart getViewPart() {
418  return fViewPart;
419  }
420 
421  public void restoreState(IMemento memento) {
422  // We don't need this here
423  }
424 
425  public void saveState(IMemento memento) {
426  // We don't need this here
427  }
428 
429  protected void handleSearchResultChanged(final SearchResultEvent e) {
430  if (e instanceof MatchEvent) {
431  postUpdate(((MatchEvent) e).getMatches());
432  } else if (e instanceof RemoveAllEvent) {
433  postClear();
434  } else if (e instanceof FilterUpdateEvent) {
435  postUpdate(((FilterUpdateEvent) e).getUpdatedMatches());
436  }
437  }
438 
439  private synchronized void postUpdate(Match[] matches) {
440  for (Match match : matches) {
441  fBatchedUpdates.add(match.getElement());
442  }
443  scheduleUIUpdate();
444  }
445 
446  private void postClear() {
447  fBatchedClearAll = true;
448  fBatchedUpdates.clear();
449  scheduleUIUpdate();
450  }
451 
452  private void asyncExec(final Runnable runnable) {
453  final Control control = getControl();
454  if (control != null && !control.isDisposed()) {
455  Display currentDisplay = Display.getCurrent();
456  if (currentDisplay == null || !currentDisplay.equals(control.getDisplay())) {
457  control.getDisplay().asyncExec(new Runnable() {
458  public void run() {
459  if (!control.isDisposed()) {
460  runnable.run();
461  }
462  }
463  });
464  } else {
465  runnable.run();
466  }
467  }
468  }
469 
470  private class UpdateUIJob extends UIJob {
471 
472  public UpdateUIJob() {
473  super("Update Search Results View");
474  setSystem(true);
475  }
476 
477  public IStatus runInUIThread(IProgressMonitor monitor) {
478  Control control = getControl();
479  if (control == null || control.isDisposed()) {
480  return Status.OK_STATUS;
481  }
482  runBatchedClear();
483  runBatchedUpdates();
484  if (hasMoreUpdates() || isQueryRunning()) {
485  schedule(1);
486  } else {
487  fIsUIUpdateScheduled = false;
488  updateBusyLabel();
489  if (fScheduleEnsureSelection) {
490  fScheduleEnsureSelection = false;
491  }
492  }
493  fViewPart.updateLabel();
494  return Status.OK_STATUS;
495  }
496 
497  private boolean hasMoreUpdates() {
498  return fBatchedClearAll || fBatchedUpdates.isEmpty();
499  }
500 
501  private void runBatchedClear() {
502  synchronized (this) {
503  if (!fBatchedClearAll) {
504  return;
505  }
506  fBatchedClearAll = false;
507  updateBusyLabel();
508  }
509  fViewPart.updateLabel();
510  fViewer.refresh();
511  }
512 
513  private synchronized void runBatchedUpdates() {
514  fViewer.refresh();
515  fBatchedUpdates.clear();
516  updateBusyLabel();
517  }
518 
519  private boolean isQueryRunning() {
520  AbstractTextSearchResult result = fInput;
521  if (result != null) {
522  return NewSearchUI.isQueryRunning(result.getQuery());
523  }
524  return false;
525  }
526 
527  @Override
528  public boolean belongsTo(Object family) {
529  return family == GitGrepSearchResultPage.this;
530  }
531  }
532 }
533 
534 class GitGrepLabelProvider extends CellLabelProvider {
535  public String getColumnText(Object element, int columnIndex) {
536  switch (columnIndex) {
537  case 0:
538  return ((GitGrepSearchResultElement) element).getObjectName();
539  case 1:
540  return ((GitGrepSearchResultElement) element).getLineNr();
541  case 2:
542  return ((GitGrepSearchResultElement) element).getContent();
543  default:
544  return "";
545  }
546  }
547 
548  public void update(ViewerCell cell) {
549  cell.setText(getColumnText((GitGrepSearchResultElement) cell.getElement(), cell.getColumnIndex()));
550  }
551 }
552 
553 class GitGrepContentProvider implements IStructuredContentProvider {
554 
555  private TableViewer paGitGrepTableViewer;
556  private GitGrepSearchResult paGitGrepSearchResult;
557 
558  public Object[] getElements(Object inputElement) {
559 
560  paGitGrepSearchResult = (GitGrepSearchResult) inputElement;
561  return paGitGrepSearchResult.getElements();
562  }
563 
564  /*
565  * (non-Javadoc)
566  *
567  * @see
568  * org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface
569  * .viewers.Viewer, java.lang.Object, java.lang.Object)
570  */
571  public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
572  paGitGrepTableViewer = (TableViewer) viewer;
573  paGitGrepSearchResult = (GitGrepSearchResult) newInput;
574  paGitGrepTableViewer.refresh();
575  }
576 
577  public void elementsChanged(Object[] updatedElements) {
578 
579  for (int i = 0; i < updatedElements.length; i++) {
580  if (paGitGrepSearchResult.getMatchCount(updatedElements[i]) > 0) {
581  if (paGitGrepTableViewer.testFindItem(updatedElements[i]) != null) {
582  paGitGrepTableViewer.refresh(updatedElements[i]);
583  } else {
584  paGitGrepTableViewer.add(updatedElements[i]);
585  }
586  } else {
587  paGitGrepTableViewer.remove(updatedElements[i]);
588  }
589  }
590  }
591 
592  @Override
593  public void dispose() {
594  // Auto-generated method stub
595  }
596 }