blob: 85987299d9b05d5f6e01cec2fd733585edc26e58 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013,2016 Ericsson and others
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Ericsson - initial API and implementation
******************************************************************************/
package org.eclipse.egerrit.internal.dashboard.ui.views;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
import org.apache.http.HttpStatus;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.egerrit.internal.core.EGerritCorePlugin;
import org.eclipse.egerrit.internal.core.GerritClient;
import org.eclipse.egerrit.internal.core.GerritCredentials;
import org.eclipse.egerrit.internal.core.GerritFactory;
import org.eclipse.egerrit.internal.core.GerritRepository;
import org.eclipse.egerrit.internal.core.GerritServerInformation;
import org.eclipse.egerrit.internal.core.ServersStore;
import org.eclipse.egerrit.internal.core.command.ChangeOption;
import org.eclipse.egerrit.internal.core.command.ChangeStatus;
import org.eclipse.egerrit.internal.core.command.QueryChangesCommand;
import org.eclipse.egerrit.internal.core.exception.EGerritException;
import org.eclipse.egerrit.internal.dashboard.core.GerritQueryException;
import org.eclipse.egerrit.internal.dashboard.ui.GerritUi;
import org.eclipse.egerrit.internal.dashboard.ui.completion.SearchContentProposalAdapter;
import org.eclipse.egerrit.internal.dashboard.ui.completion.SearchContentProposalProvider;
import org.eclipse.egerrit.internal.dashboard.ui.model.UIReviewTable;
import org.eclipse.egerrit.internal.dashboard.ui.preferences.Utils;
import org.eclipse.egerrit.internal.dashboard.ui.utils.SelectionDialog;
import org.eclipse.egerrit.internal.dashboard.ui.utils.UIUtils;
import org.eclipse.egerrit.internal.dashboard.utils.GerritServerUtility;
import org.eclipse.egerrit.internal.model.ChangeInfo;
import org.eclipse.egerrit.internal.model.ModelFactory;
import org.eclipse.egerrit.internal.model.Reviews;
import org.eclipse.egerrit.internal.ui.editors.ChangeDetailEditor;
import org.eclipse.egerrit.internal.ui.editors.model.ChangeDetailEditorInput;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
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.Link;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.ViewPart;
import org.osgi.framework.Version;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// need our own to handle query result
/**
* The gerrit dashboard
*/
public class GerritTableView extends ViewPart {
private static Logger logger = LoggerFactory.getLogger(GerritTableView.class);
/**
* The ID of the view as specified by the extension.
*/
public static final String VIEW_ID = "org.eclipse.egerrit.dashboard.ui.views.GerritTableView"; //$NON-NLS-1$
private static final int SEARCH_WIDTH = 350;
//Numbers of menu items in the Search pulldown menu; SEARCH_SIZE_MENU_LIST + 1 will be the max
private static final int SEARCH_SIZE_MENU_LIST = 4;
private static final String TITLE = "Gerrit Server "; //$NON-NLS-1$
private static final String CHECKED_IMAGE = "personSignIn.png"; //$NON-NLS-1$
private static final String ANONYMOUS_IMAGE = "personAnonymous.png"; //$NON-NLS-1$
private static final String INVALID_IMAGE = "personInvalid.png"; //$NON-NLS-1$
private static final String JOB_FAMILY = "DASHBOARD_UI"; //$NON-NLS-1$
private AddOneServerDialog fAddOneServerDialog = null;
// For the images
private static ImageRegistry fImageRegistry = new ImageRegistry();
static {
String iconPath = "icons/view16/"; //$NON-NLS-1$
fImageRegistry.put(CHECKED_IMAGE, GerritUi.getImageDescriptor(iconPath + CHECKED_IMAGE));
fImageRegistry.put(ANONYMOUS_IMAGE, GerritUi.getImageDescriptor(iconPath + ANONYMOUS_IMAGE));
fImageRegistry.put(INVALID_IMAGE, GerritUi.getImageDescriptor(iconPath + INVALID_IMAGE));
}
// ------------------------------------------------------------------------
// Member variables
// ------------------------------------------------------------------------
private Composite fTopComposite = null;
private GerritServerInformation defaultServerInfo = null;
private static GerritTableView rtv = null;
private CLabel fRepositoryVersionResulLabel;
private Label fReviewsTotalLabel;
private Combo fSearchTextBox;
private Button fSearchRequestBtn;
private Set<String> fRequestList = new LinkedHashSet<>();
private TableViewer fViewer;
private GerritServerUtility fServerUtil = GerritServerUtility.getInstance();
private List<GerritServerInformation> fMapRepoServer = null;
private Action doubleClickAction;
private final LinkedHashSet<Job> fJobs = new LinkedHashSet<>();
private GerritClient gerritClient = null;
private Composite parentComposite;
private Composite searchSection;
private UIReviewTable reviewTable;
private SearchContentProposalProvider searchProposalProvider = new SearchContentProposalProvider(() -> {
initializeDefaultServer();
if (defaultServerInfo != null) {
connectToServer(defaultServerInfo);
}
});
// ------------------------------------------------------------------------
// Constructor and life cycle
// ------------------------------------------------------------------------
/**
* The constructor.
*/
public GerritTableView() {
super();
rtv = this;
}
/* (non-Javadoc)
* @see org.eclipse.ui.part.WorkbenchPart#dispose()
*/
@Override
public void dispose() {
cleanJobs();
if (reviewTable != null) {
reviewTable.dispose();
}
rtv = null;
}
private void cleanJobs() {
Iterator<Job> iter = fJobs.iterator();
while (iter.hasNext()) {
Job job = iter.next();
job.sleep();
job.cancel();
}
fJobs.clear();
}
/**
* Refresh the table and other fields that show information related to what is in the table
*/
private void refresh(Reviews reviews) {
Display.getDefault().asyncExec(() -> {
if (!fViewer.getTable().isDisposed()) {
fViewer.setInput(reviews);
//Refresh the counter
setReviewsTotalResultLabel(Integer.toString(reviews.getAllReviews().size()));
searchSection.layout(true);
}
});
}
/* (non-Javadoc)
* @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createPartControl(Composite aParent) {
parentComposite = aParent;
if (fServerUtil.getLastSavedGerritServer() == null) {
createEmptyPage(ServersStore.getAllServers().isEmpty());
} else {
createReviewList(null);
}
}
private void createEmptyPage(boolean enterNewServer) {
removeExistingWidgets();
Color background = parentComposite.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND);
Composite composite = new Composite(parentComposite, SWT.NONE);
composite.setLayout(new GridLayout(1, false));
composite.setBackground(background);
Link link = new Link(composite, SWT.NONE);
if (enterNewServer) {
link.setText(Messages.Welcome_No_Server);
link.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
addOrChangeServerThenLoad();
}
});
} else {
link.setText(Messages.Welcome_Pick_Server);
link.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
GerritServerInformation server = askUserToSelectRepo(ServersStore.getAllServers());
if (server != null) {
fServerUtil.saveLastGerritServer(server);
processCommands(ChangeStatus.OPEN.getValue());
}
}
});
}
link.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, true, false));
link.setBackground(background);
}
private void createReviewList(String[] voteColumns) {
String[] reviewVoteColumns;
if (voteColumns == null) {
reviewVoteColumns = new String[0];
} else {
reviewVoteColumns = voteColumns.clone();
}
removeExistingWidgets();
fTopComposite = new Composite(parentComposite, SWT.NONE);
fTopComposite.setLayout(new GridLayout(1, true));
searchSection = createSearchSection(fTopComposite);
searchSection.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
createTable(reviewVoteColumns);
}
private void createTable(String[] voteColumns) {
if (fViewer != null) {
//Destroy the table before creating a new one
fViewer.getControl().dispose();
fViewer = null;
}
Display.getDefault().syncExec(() -> {
reviewTable = new UIReviewTable();
reviewTable.createTableViewerSection(fTopComposite, voteColumns)
.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
fViewer = reviewTable.getViewer();
getSite().setSelectionProvider(fViewer);
makeActions();
hookDoubleClickAction();
parentComposite.layout(true); //Here we force a re-layout
VoteToolTipHandler voteHandler = new VoteToolTipHandler(fTopComposite.getShell(), rtv);
voteHandler.connect();
});
}
private void removeExistingWidgets() {
for (Control control : parentComposite.getChildren()) {
control.dispose();
}
}
/**
* Create a group to show the search command and a search text
*
* @param Composite
* aParent
*/
private Composite createSearchSection(Composite aParent) {
final Composite searchComposite = new Composite(aParent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 4;
layout.marginTop = 0;
layout.marginHeight = 0;
layout.verticalSpacing = 0;
layout.makeColumnsEqualWidth = false;
searchComposite.setLayout(layout);
//Label to display the repository and the version
fRepositoryVersionResulLabel = new CLabel(searchComposite, SWT.LEFT_TO_RIGHT);
GridData labelGridData = new GridData(SWT.LEFT, SWT.CENTER, false, false);
fRepositoryVersionResulLabel.setLayoutData(labelGridData);
fRepositoryVersionResulLabel.addMouseListener(connectToServerListener());
//Label to display Total reviews
fReviewsTotalLabel = new Label(searchComposite, SWT.NONE);
GridData totalLabelGridData = new GridData(SWT.LEFT, SWT.CENTER, false, false);
totalLabelGridData.horizontalIndent = 10;
fReviewsTotalLabel.setLayoutData(totalLabelGridData);
//Create a SEARCH text data entry
fSearchTextBox = new Combo(searchComposite, SWT.NONE);
// Create a content proposal for the search box
new SearchContentProposalAdapter(fSearchTextBox, searchProposalProvider);
GridData searchGridData = new GridData(SWT.RIGHT, SWT.CENTER, true, false);
searchGridData.widthHint = SEARCH_WIDTH;
searchGridData.minimumWidth = 100;
fSearchTextBox.setLayoutData(searchGridData);
fSearchTextBox.setToolTipText(Messages.GerritTableView_tooltipSearch);
//Get the last saved commands
fRequestList = fServerUtil.getListLastCommands();
setSearchText(""); //$NON-NLS-1$
fSearchTextBox.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
Object obj = e.getSource();
if (obj instanceof Combo) {
Combo combo = (Combo) obj;
//Always let this request go through, even if the user
//is requesting the same search as before; this gives
//another way to refresh the dashboard.
processCommands(combo.getText());
}
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
//Handle the CR in the search text
if (fSearchTextBox.getText().trim().length() > 0) {
processCommands(fSearchTextBox.getText());
}
}
});
//Create a SEARCH button
fSearchRequestBtn = new Button(searchComposite, SWT.NONE);
fSearchRequestBtn.setText(Messages.GerritTableView_search);
fSearchRequestBtn.setLayoutData(new GridData(SWT.RIGHT, SWT.NONE, false, false));
fSearchRequestBtn.addListener(SWT.Selection, event -> processCommands(fSearchTextBox.getText()));
adaptSearchSectionLayout(searchComposite);
return searchComposite;
}
private void adaptSearchSectionLayout(final Composite composite) {
composite.addControlListener(new ControlListener() {
boolean searchOnly = false;
@Override
public void controlResized(ControlEvent e) {
Rectangle size = composite.getClientArea();
if (size.width > 300 && searchOnly) {
//Show all widgets
((GridData) fRepositoryVersionResulLabel.getLayoutData()).exclude = false;
((GridData) fReviewsTotalLabel.getLayoutData()).exclude = false;
((GridData) fSearchRequestBtn.getLayoutData()).exclude = false;
fRepositoryVersionResulLabel.setVisible(true);
fReviewsTotalLabel.setVisible(true);
fSearchRequestBtn.setVisible(true);
searchOnly = false;
composite.layout(true);
return;
}
if (size.width < 300 && !searchOnly) {
//Hide all widgets except the search drop down
((GridData) fRepositoryVersionResulLabel.getLayoutData()).exclude = true;
((GridData) fReviewsTotalLabel.getLayoutData()).exclude = true;
((GridData) fSearchRequestBtn.getLayoutData()).exclude = true;
fRepositoryVersionResulLabel.setVisible(false);
fReviewsTotalLabel.setVisible(false);
fSearchRequestBtn.setVisible(false);
searchOnly = true;
composite.layout(true);
return;
}
}
@Override
public void controlMoved(ControlEvent e) {
}
});
}
/**
* This method is the listener to let user connect to a server
*
* @return MouseAdapter
*/
private MouseAdapter connectToServerListener() {
return new MouseAdapter() {
@Override
public void mouseDown(MouseEvent e) {
if ((gerritClient == null) || (gerritClient.getRepository().getServerInfo().isAnonymous())) {
addOrChangeServerThenLoad();
}
}
};
}
private void makeActions() {
doubleClickAction = new Action() {
@Override
public void run() {
// -------------------------------------------------
// Open an editor on the provided server and changeInfo
// -------------------------------------------------
ISelection selection = fViewer.getSelection();
if (!(selection instanceof IStructuredSelection)) {
return;
}
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
verifySelectionToOpen(structuredSelection);
}
/**
* @param structuredSelection
*/
private void verifySelectionToOpen(IStructuredSelection structuredSelection) {
Iterator<?> selections = structuredSelection.iterator();
while (selections.hasNext()) {
Object element = selections.next();
if (element instanceof ChangeInfo) {
openEditorWithInfo((ChangeInfo) element);
}
}
}
/**
* @param changeInfo
*/
private void openEditorWithInfo(ChangeInfo changeInfo) {
IWorkbenchPage page = getActivePage();
if (page != null) {
try {
IEditorInput input = new ChangeDetailEditorInput(gerritClient, changeInfo);
IEditorPart reusedEditor = page.findEditor(input);
page.openEditor(input, ChangeDetailEditor.EDITOR_ID);
if (reusedEditor instanceof ChangeDetailEditor) {
((ChangeDetailEditor) reusedEditor).refreshStatus();
}
} catch (PartInitException e) {
EGerritCorePlugin.logError(gerritClient != null
? gerritClient.getRepository().formatGerritVersion() + e.getMessage()
: e.getMessage());
}
}
}
/**
* @return
*/
private IWorkbenchPage getActivePage() {
IWorkbench workbench = GerritUi.getDefault().getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
IWorkbenchPage page = null;
if (window != null) {
page = workbench.getActiveWorkbenchWindow().getActivePage();
}
return page;
}
};
}
private void hookDoubleClickAction() {
fViewer.addDoubleClickListener(event -> doubleClickAction.run());
}
/**
* Passing the focus request to the viewer's control.
*/
@Override
public void setFocus() {
parentComposite.setFocus();
}
public TableViewer getTableViewer() {
return fViewer;
}
public static GerritTableView getActiveView(boolean forceOpen) {
IViewPart viewPart = null;
if (rtv != null) {
return rtv;
} else {
if (!forceOpen) {
return null;
}
IWorkbench workbench = GerritUi.getDefault().getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
IWorkbenchPage page = null;
if (window != null) {
page = workbench.getActiveWorkbenchWindow().getActivePage();
}
if (page != null) {
viewPart = page.findView(VIEW_ID);
// The following can occurs in LINUX environment since
// killing the window call the dispose() method
if (viewPart == null) {
try {
viewPart = page.showView(VIEW_ID, null, org.eclipse.ui.IWorkbenchPage.VIEW_CREATE);
} catch (PartInitException e) {
logger.warn(e.getMessage());
}
logger.debug("getActiveView() SHOULD (JUST) CREATED A NEW Table:" + viewPart); //$NON-NLS-1$
}
}
return (GerritTableView) viewPart;
}
}
/**
* bring the Gerrit Dashboard view visible to the current workbench
*/
public void openView() {
IWorkbench workbench = GerritUi.getDefault().getWorkbench();
IWorkbenchPage page = workbench.getActiveWorkbenchWindow().getActivePage();
IViewPart viewPart = page.findView(VIEW_ID);
// if the review view is not showed yet,
if (viewPart == null) {
try {
page.showView(VIEW_ID);
} catch (PartInitException e) {
logger.warn(e.getMessage());
}
}
// if there exists the view, but if not on the top,
// then brings it to top when the view is already showed.
else if (!page.isPartVisible(viewPart)) {
page.bringToTop(viewPart);
}
}
/**
* Process the commands based on the Gerrit string
*
* @param String
* aQuery
*/
public void processCommands(String aQuery) {
logger.debug("Process command : " + aQuery); //$NON-NLS-1$
defaultServerInfo = null;
String httpQuery = handleHttpInQuery(aQuery);
initializeDefaultServer();
//We should have a Gerrit Server here, otherwise, the user need to define one
if (defaultServerInfo == null) {
UIUtils.showNoServerMessage();
//Only one instance of the pop-up
if (fAddOneServerDialog == null) {
fAddOneServerDialog = new AddOneServerDialog();
Display.getDefault().syncExec(() -> fAddOneServerDialog.promptForNewServer(true));
defaultServerInfo = fAddOneServerDialog.getServer();
fAddOneServerDialog = null; //reset the instance
if (defaultServerInfo == null) {
logger.debug("No new server entered by the user. "); //$NON-NLS-1$
return;
}
}
}
//At this point we have a server, execute the query if we can
if (httpQuery != null && !"".equals(httpQuery)) { //$NON-NLS-1$
updateTable(defaultServerInfo, httpQuery);
}
}
private void initializeDefaultServer() {
//Use the last server if no server got discovered
if (defaultServerInfo == null) {
GerritServerInformation lastServer = fServerUtil.getLastSavedGerritServer();
if (lastServer != null) {
//Already saved a Gerrit server, so use it
defaultServerInfo = lastServer;
}
}
//No last server was specified, get a server by prompting the user or picking the first one
if (defaultServerInfo == null) {
fMapRepoServer = ServersStore.getAllServers();
if (fMapRepoServer.size() == 1) {
defaultServerInfo = fMapRepoServer.get(0);
} else if (fMapRepoServer.size() > 1) {
defaultServerInfo = askUserToSelectRepo(ServersStore.getAllServers());
}
}
if (defaultServerInfo != null) {
fServerUtil.saveLastGerritServer(defaultServerInfo);
}
}
private String handleHttpInQuery(String aQuery) {
String latestQuery = aQuery;
ChangeIdExtractor extractedData = new ChangeIdExtractor(aQuery);
if (extractedData.getServer() != null) {
selectServer(extractedData.getServer());
if (extractedData.getChangeId() != null) {
latestQuery = "change:" + extractedData.getChangeId(); //$NON-NLS-1$
} else {
latestQuery = ChangeStatus.OPEN.getValue();
}
}
return latestQuery;
}
private void selectServer(GerritServerInformation server) {
List<GerritServerInformation> matches = findOrAddMatchingServers(server);
if (matches.size() == 1) {
defaultServerInfo = matches.get(0);
return;
}
defaultServerInfo = askUserToSelectRepo(matches);
}
private List<GerritServerInformation> findOrAddMatchingServers(GerritServerInformation searched) {
List<GerritServerInformation> knownServers = ServersStore.getAllServers();
List<GerritServerInformation> matches = new ArrayList<>();
List<GerritServerInformation> bestMatches = new ArrayList<>();
//Best matches are those with the same URI and a username
//Second best matches are servers with URIs
for (GerritServerInformation candidate : knownServers) {
if (candidate.getServerURI().equals(searched.getServerURI())) {
if (candidate.getUserName().equals(searched.getUserName())) {
bestMatches.add(0, candidate);
} else {
matches.add(candidate);
}
}
}
//Return the best matches if we have any
if (!bestMatches.isEmpty()) {
return bestMatches;
}
//No match at all, then we will the one we have
if (matches.isEmpty()) {
knownServers.add(searched);
ServersStore.saveServers(knownServers);
matches.add(searched);
}
return matches;
}
/**
* Process the command to set the Starred flag on the Gerrit server String taskId boolean starred
*
* @return void
* @throws CoreException
*/
public void setStarred(ChangeInfo changeInfo, boolean starred) throws CoreException {
if (defaultServerInfo == null) {
UIUtils.showNoServerMessage();
} else {
if (starred) {
CompletableFuture.runAsync(() -> {
try {
gerritClient.starChange(changeInfo).call();
} catch (EGerritException e) {
EGerritCorePlugin.logInfo(gerritClient.getRepository().formatGerritVersion() + e.getMessage());
}
});
} else {
CompletableFuture.runAsync(() -> {
try {
gerritClient.unstarChange(changeInfo).call();
} catch (EGerritException e) {
EGerritCorePlugin.logError(gerritClient.getRepository().formatGerritVersion() + e.getMessage());
}
});
}
}
}
/**
* Find the last Gerrit server being used , otherwise consider the Eclipse.org gerrit server version as a default
*
* @return Version
*/
private Version getlastGerritServerVersion() {
Version version = null;
GerritServerInformation lastSaved = fServerUtil.getLastSavedGerritServer();
if (lastSaved != null) {
//Already saved a Gerrit server, so use it
defaultServerInfo = lastSaved;
}
if (defaultServerInfo == null) {
//If we did not find the task Repository
fMapRepoServer = ServersStore.getAllServers();
//Verify How many gerrit server are defined
if (fMapRepoServer.size() == 1) {
for (GerritServerInformation key : fMapRepoServer) {
defaultServerInfo = key;
//Save it for the next query time
fServerUtil.saveLastGerritServer(key);
break;
}
}
}
return version;
}
/**
* Verify if the Gerrit version is before 2.5
*
* @return boolean
*/
public boolean isGerritVersionBefore_2_5() {
boolean ret = false;
Version version = getlastGerritServerVersion();
if (version != null && version.getMajor() >= 2 && version.getMinor() < 5) {
ret = true;
}
return ret;
}
/**
* @param server
* @param aQueryType
*/
private void updateTable(final GerritServerInformation server, final String aQueryType) {
createReviewList(null);
String cmdMessage = NLS.bind(Messages.GerritTableView_commandMessage, server.getServerURI(), aQueryType);
final Job job = new Job(cmdMessage) {
@Override
public boolean belongsTo(Object aFamily) {
return JOB_FAMILY.equals(aFamily);
}
@Override
public IStatus run(final IProgressMonitor aMonitor) {
// If there is only have one Gerrit server, we can proceed as if it was already used before
IStatus status = null;
try {
status = getReviews(server, aQueryType);
if (status.isOK()) {
Display.getDefault().syncExec(() -> setSearchText(aQueryType));
}
status = Status.OK_STATUS;
} catch (GerritQueryException e) {
status = e.getStatus();
logger.error(e.getMessage());
}
aMonitor.done();
fJobs.remove(this);
return status;
}
};
//Clean some Jobs if still running
cleanJobs();
fJobs.add(job);
job.setUser(true);
job.schedule();
}
//Display a query string in the search text.
private void setSearchText(String aSt) {
if (!fSearchTextBox.isDisposed()) {
if (aSt != null && aSt != "") { //$NON-NLS-1$
String[] ar = fSearchTextBox.getItems();
int index = findSearchBoxIndexCombo(aSt, ar);
removeElementSearchComboList(ar, index);
//Add the new text in the combo
fRequestList.add(aSt.trim());
//Save the list of commands in file
fServerUtil.saveLastCommandList(fRequestList);
}
adjustSearchBox(aSt);
}
}
/**
* @param ar
* @param index
*/
private void removeElementSearchComboList(String[] ar, int index) {
if (index != -1) {
fRequestList.remove(ar[index]);
} else {
//Remove the oldest element from the list
if (fRequestList.size() > SEARCH_SIZE_MENU_LIST) {
Object obj = fRequestList.iterator().next(); //Should be the first item in the list
fRequestList.remove(obj);
}
}
}
/**
* @param aSt
* @param index
* @param ar
* @return
*/
private int findSearchBoxIndexCombo(String aSt, String[] ar) {
int index = -1;
for (int i = 0; i < ar.length; i++) {
if (ar[i].equals(aSt.trim())) {
index = i;
break;
}
}
return index;
}
/**
* @param aSt
*/
private void adjustSearchBox(String aSt) {
fSearchTextBox.setItems(reverseOrder(fRequestList.toArray(new String[0])));
if (aSt != null && aSt != "") { //$NON-NLS-1$
fSearchTextBox.select(0);
} else {
//Leave the text empty
fSearchTextBox.setText(""); //$NON-NLS-1$
}
}
/**
* Take the list of last save queries and reverse the order to have the latest selection to be the first one on the
* pull-down menu
*
* @param aList
* String[]
* @return String[] reverse order
*/
private String[] reverseOrder(String[] aList) {
int size = aList.length;
int index = size - 1;
String[] rev = new String[size];
for (int i = 0; i < size; i++) {
rev[i] = aList[index--];
}
return rev;
}
private void displayInformation(final String server, final String st) {
Display.getDefault().syncExec(
() -> MessageDialog.openInformation(null, NLS.bind(Messages.GerritTableView_information, server), st));
}
/**
* Perform the requested query and convert the resulting tasks in GerritTask:s
*
* @param repository
* the tasks repository
* @param queryType
* the query
* @return IStatus
* @throws GerritQueryException
*/
private IStatus getReviews(GerritServerInformation repository, String queryType) throws GerritQueryException {
if (!connectToServer(repository)) {
return Status.CANCEL_STATUS;
}
if (!isQueryAuthorized(queryType)) {
displayInformation(repository.getServerURI(),
NLS.bind(Messages.GerritTableView_informationAnonymous, queryType));
return Status.CANCEL_STATUS;
}
// Format the query id
String queryString = queryType;
IStatus ret = Status.OK_STATUS;
Reviews shownReviews = ModelFactory.eINSTANCE.createReviews();
if (gerritClient != null) {
// Fetch the list of reviews and pre-populate the table
ChangeInfo[] loadedReviews = getReviewList(queryString);
// Get the name of the columns for the votes and setup the table
String[] columns = extractColumnNames(loadedReviews);
Display.getDefault().syncExec(() -> createReviewList(columns));
if (loadedReviews != null) {
for (ChangeInfo review : loadedReviews) {
shownReviews.getAllReviews().add(review);
}
} else {
shownReviews.getAllReviews().clear();
ret = new Status(IStatus.ERROR, EGerritCorePlugin.PLUGIN_ID, "Error"); //$NON-NLS-1$
}
setRepositoryVersionLabel(defaultServerInfo.getName(),
gerritClient.getRepository().getVersion().toString());
} else {
//Reset the list to prevent bad request
shownReviews.getAllReviews().clear();
fServerUtil.resetLastGerritServer();
setRepositoryVersionLabel(Messages.Invalid_server, Messages.No_Connection);
ret = new Status(IStatus.ERROR, EGerritCorePlugin.PLUGIN_ID, "Error"); //$NON-NLS-1$
}
if (shownReviews.getAllReviews() != null) {
refresh(shownReviews);
}
return ret;
}
private boolean connectToServer(GerritServerInformation repository) {
URI uri = null;
try {
if (!repository.getServerURI().isEmpty()) {
uri = new URI(repository.getServerURI());
}
} catch (URISyntaxException e) {
EGerritCorePlugin.logError(gerritClient != null
? gerritClient.getRepository().formatGerritVersion() + e.getMessage()
: e.getMessage());
}
if (uri != null) {
String scheme = uri.getScheme();
String host = uri.getHost();
int port = uri.getPort();
String path = uri.getPath();
String user = repository.getUserName();
String passwd = repository.getPassword();
GerritCredentials creds = new GerritCredentials(user, passwd);
// Initialize
GerritRepository gerritRepository = new GerritRepository(scheme, host, port, path);
gerritRepository.setCredentials(creds);
gerritRepository.setServerInfo(repository);
gerritRepository.acceptSelfSignedCerts(repository.getSelfSigned());
gerritClient = gerritRepository.instantiateGerrit();
searchProposalProvider.setGerritClient(gerritClient);
boolean connect = gerritRepository.connect();
if (connect) {
return showVersionError(gerritRepository);
} else if (gerritRepository.getStatus() == HttpStatus.SC_UNAUTHORIZED) {
UIUtils.showErrorDialog(Messages.Server_connection_401_title,
NLS.bind(Messages.Server_connection_401, gerritRepository.getPath()));
return false;
}
return connect;
}
return false;
}
/**
* @param gerritRepository
*/
private boolean showVersionError(GerritRepository gerritRepository) {
Version version = gerritRepository.getVersion();
if (version == null) {
UIUtils.showErrorDialog(Messages.Invalid_Credentials, "Server " + defaultServerInfo.getServerURI()); //$NON-NLS-1$
return false;
} else if (version.equals(GerritRepository.NO_VERSION)) {
UIUtils.showErrorDialog(Messages.Unsupported_server_version_title,
NLS.bind(Messages.Unsupported_server_version, GerritFactory.MINIMAL_VERSION));
return false;
} else if (version.compareTo(GerritFactory.MINIMAL_VERSION) < 0) {
UIUtils.showErrorDialog(Messages.Unsupported_Server_Version,
NLS.bind(Messages.Unsupported_server_version, GerritFactory.MINIMAL_VERSION));
return false;
}
return true;
}
private ChangeInfo[] getReviewList(String aQuery) throws GerritQueryException {
ChangeInfo[] reviews = null;
try {
reviews = performQuery(aQuery, new NullProgressMonitor());
} catch (MalformedURLException e) {
EGerritCorePlugin.logError(gerritClient != null
? gerritClient.getRepository().formatGerritVersion() + e.getMessage()
: e.getMessage());
}
return reviews;
}
private ChangeInfo[] performQuery(String query, IProgressMonitor monitor) throws MalformedURLException {
try {
monitor.beginTask("Executing query", IProgressMonitor.UNKNOWN); //$NON-NLS-1$
ChangeInfo[] res = null;
QueryChangesCommand command = gerritClient.queryChanges();
command.addOption(ChangeOption.LABELS);
command.addOption(ChangeOption.DETAILED_LABELS);
command.addOption(ChangeOption.DETAILED_ACCOUNTS);
command.addOption(ChangeOption.MESSAGES);
command.addOption(ChangeOption.CURRENT_REVISION);
command.addOption(ChangeOption.CURRENT_COMMIT);
command.addOption(ChangeOption.CURRENT_ACTIONS);
try {
command.addQuery(query);
res = command.call();
} catch (EGerritException e) {
Utils.displayInformation(null, TITLE, e.getLocalizedMessage());
}
return res;
} finally {
monitor.done();
}
}
private boolean isQueryAuthorized(String query) {
if (!query.isEmpty()) {
if (gerritClient.getRepository().getServerInfo().isAnonymous() && (query.contains(":self") //$NON-NLS-1$
|| query.contains(":owner") || query.contains("is:reviewer") || query.contains("is:starred") //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
|| query.contains(":draft"))) { //$NON-NLS-1$
return false;
}
}
return true;
}
private void setRepositoryVersionLabel(String aRepo, String aVersion) {
Display.getDefault().asyncExec(() -> {
if (!fRepositoryVersionResulLabel.isDisposed()) {
// e.g. "Eclipse.org Reviews - Gerrit 2.6.1"
fRepositoryVersionResulLabel.setText(aRepo);
if (gerritClient == null) {
fRepositoryVersionResulLabel.setImage(fImageRegistry.get(INVALID_IMAGE));
fRepositoryVersionResulLabel.setToolTipText(Messages.GerritTableView_tooltipInvalid);
} else if (gerritClient.getRepository().getServerInfo().isAnonymous()) {
fRepositoryVersionResulLabel.setImage(fImageRegistry.get(ANONYMOUS_IMAGE));
fRepositoryVersionResulLabel.setToolTipText(Messages.GerritTableView_tooltipAnonymous + '\n'
+ NLS.bind(Messages.GerritTableView_gerritVersion, aVersion));
} else {
fRepositoryVersionResulLabel.setImage(fImageRegistry.get(CHECKED_IMAGE));
fRepositoryVersionResulLabel.setToolTipText(NLS.bind(Messages.GerritTableView_tooltipLoggedOnAs,
gerritClient.getRepository().getServerInfo().getUserName()) + '\n'
+ NLS.bind(Messages.GerritTableView_gerritVersion, aVersion));
}
}
});
}
private void setReviewsTotalResultLabel(String aSt) {
if (!fReviewsTotalLabel.isDisposed()) {
fReviewsTotalLabel.setText(Messages.GerritTableView_totalReview + aSt);
}
}
private GerritServerInformation askUserToSelectRepo(List<GerritServerInformation> servers) {
GerritServerInformation selection = null;
SelectionDialog taskSelection = new SelectionDialog(null, servers);
if (taskSelection.open() == Window.OK) {
selection = taskSelection.getSelection();
}
if (selection != null) {
createReviewList(null);
}
return selection;
}
private void addOrChangeServerThenLoad() {
//Only one instance of the pop-up
if (fAddOneServerDialog == null) {
fAddOneServerDialog = new AddOneServerDialog();
fAddOneServerDialog.promptToModifyServer(defaultServerInfo, true);
GerritServerInformation serverInfo = fAddOneServerDialog.getServer();
fAddOneServerDialog = null; //Reset the instance
if (serverInfo == null) {
logger.debug("No new server entered by the user."); //$NON-NLS-1$
return;
}
defaultServerInfo = serverInfo; //Set the default server with the latest value
if (fSearchTextBox == null || fSearchTextBox.getText().isEmpty()) {
processCommands(ChangeStatus.OPEN.getValue());
} else {
processCommands(fSearchTextBox.getText());
}
}
}
/**
* Process a query to update the dashboard table.
*/
public void update() {
rtv.processCommands(fSearchTextBox.getText());
}
/**
* Perform an update according to the parameter received
*
* @param query
*/
public void update(String query) {
rtv.processCommands(query);
}
/**
* Get the defined GerritClient
*
* @return
*/
public GerritClient getGerritClient() {
return gerritClient;
}
/**
* Reset the table to its initial value
*/
public void resetDefault() {
reviewTable.resetDefault();
}
/**
* From the changeInfo, extract and sort the allowed labels
*
* @return
*/
private String[] extractColumnNames(ChangeInfo[] reviews) {
TreeSet<String> allLabels = new TreeSet<>();
if (reviews == null || reviews.length == 0) {
return new String[0];
}
for (ChangeInfo changeinfo : reviews) {
allLabels.addAll(changeinfo.getLabels().keySet());
}
return allLabels.toArray(new String[allLabels.size()]);
}
/**
* @return the UIReviewTable
*/
public UIReviewTable getReviewTable() {
return reviewTable;
}
}