/*
* SonarLint for Eclipse
* Copyright (C) 2015-2017 SonarSource SA
* sonarlint@sonarsource.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonarlint.eclipse.ui.internal.server;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.Display;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IDecoratorManager;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionContext;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.navigator.CommonNavigator;
import org.eclipse.ui.navigator.CommonViewer;
import org.eclipse.ui.navigator.CommonViewerSiteFactory;
import org.eclipse.ui.navigator.ICommonViewerSite;
import org.eclipse.ui.navigator.NavigatorActionService;
import org.eclipse.ui.part.PageBook;
import org.sonarlint.eclipse.core.internal.SonarLintCorePlugin;
import org.sonarlint.eclipse.core.internal.server.IServer;
import org.sonarlint.eclipse.core.internal.server.IServerLifecycleListener;
import org.sonarlint.eclipse.core.internal.server.IServerListener;
import org.sonarlint.eclipse.ui.internal.Messages;
import org.sonarlint.eclipse.ui.internal.SonarLintUiPlugin;
import org.sonarlint.eclipse.ui.internal.server.wizard.NewServerLocationWizard;
/**
* A view of servers, their modules, and status.
*/
public class ServersView extends CommonNavigator {
public static final String ID = SonarLintUiPlugin.PLUGIN_ID + ".ServersView";
private static final String SERVERS_VIEW_CONTEXT = "org.eclipse.ui.sonarlintServerViewScope";
protected CommonViewer tableViewer;
private Control mainPage;
private Control noServersPage;
private PageBook book;
private IServerLifecycleListener serverResourceListener;
private IServerListener serverListener;
/**
* ServersView constructor comment.
*/
public ServersView() {
super();
}
@Override
public void createPartControl(Composite parent) {
// Add PageBook as parent composite
FormToolkit toolkit = new FormToolkit(parent.getDisplay());
book = new PageBook(parent, SWT.NONE);
super.createPartControl(book);
// Main page for the Servers tableViewer
mainPage = getCommonViewer().getControl();
// Page prompting to define a new server
noServersPage = createDefaultPage(toolkit);
book.showPage(mainPage);
IContextService contextSupport = (IContextService) getSite().getService(IContextService.class);
contextSupport.activateContext(SERVERS_VIEW_CONTEXT);
deferInitialization();
}
/**
* Creates a page displayed when there are no servers defined.
*
* @param kit
* @return Control
*/
private Control createDefaultPage(FormToolkit kit) {
Form form = kit.createForm(book);
Composite body = form.getBody();
GridLayout layout = new GridLayout(2, false);
body.setLayout(layout);
Link hlink = new Link(body, SWT.NONE);
hlink.setText(Messages.ServersView_noServers);
hlink.setBackground(book.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
GridData gd = new GridData(SWT.LEFT, SWT.FILL, true, false);
hlink.setLayoutData(gd);
hlink.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
NewServerLocationWizard wizard = new NewServerLocationWizard();
WizardDialog wd = new WizardDialog(book.getShell(), wizard);
if (wd.open() == Window.OK) {
toggleDefaultPage();
}
}
});
// Create the context menu for the default page
final CommonViewer commonViewer = this.getCommonViewer();
if (commonViewer != null) {
ICommonViewerSite commonViewerSite = CommonViewerSiteFactory
.createCommonViewerSite(this.getViewSite());
if (commonViewerSite != null) {
// Note: actionService cannot be null
final NavigatorActionService actionService = new NavigatorActionService(commonViewerSite,
commonViewer, commonViewer.getNavigatorContentService());
MenuManager menuManager = new MenuManager("#PopupMenu");
menuManager.addMenuListener(mgr -> {
ISelection selection = commonViewer.getSelection();
actionService.setContext(new ActionContext(selection));
actionService.fillContextMenu(mgr);
});
Menu menu = menuManager.createContextMenu(body);
// It is necessary to set the menu in two places:
// 1. The white space in the server view
// 2. The text and link in the server view. If this menu is not set, if the
// user right clicks on the text or uses shortcut keys to open the context menu,
// the context menu will not come up
body.setMenu(menu);
hlink.setMenu(menu);
}
}
return form;
}
/**
* Switch between the servers and default/empty page.
*
*/
void toggleDefaultPage() {
if (tableViewer.getTree().getItemCount() < 1) {
book.showPage(noServersPage);
} else {
book.showPage(mainPage);
}
}
private void deferInitialization() {
Job job = new Job(Messages.jobInitializingServersView) {
@Override
public IStatus run(IProgressMonitor monitor) {
deferredInitialize();
return Status.OK_STATUS;
}
};
job.setSystem(true);
job.setPriority(Job.SHORT);
job.schedule();
}
protected void deferredInitialize() {
addListener();
Display.getDefault().asyncExec(() -> {
try {
tableViewer = getCommonViewer();
getSite().setSelectionProvider(tableViewer);
try {
if (tableViewer.getTree().getItemCount() > 0) {
Object obj = tableViewer.getTree().getItem(0).getData();
tableViewer.setSelection(new StructuredSelection(obj));
} else {
toggleDefaultPage();
}
} catch (Exception e1) {
throw new IllegalStateException("Unable to update servers", e1);
}
} catch (Exception e2) {
// ignore - view has already been closed
}
});
}
protected void refreshServerContent(final IServer server) {
Display.getDefault().asyncExec(() -> {
if (!tableViewer.getTree().isDisposed()) {
tableViewer.refresh(server, true);
}
});
}
protected void refreshServerState() {
Display.getDefault().asyncExec(() -> {
IDecoratorManager dm = PlatformUI.getWorkbench().getDecoratorManager();
dm.update(ServerDecorator.ID);
if (tableViewer != null) {
tableViewer.setSelection(tableViewer.getSelection());
}
});
}
protected void addListener() {
// To enable the UI updating of servers and its childrens
serverResourceListener = new IServerLifecycleListener() {
@Override
public void serverAdded(IServer server) {
addServer(server);
server.addServerListener(serverListener);
}
@Override
public void serverChanged(IServer server) {
refreshServerContent(server);
}
@Override
public void serverRemoved(IServer server) {
removeServer(server);
server.removeServerListener(serverListener);
}
};
SonarLintCorePlugin.getServersManager().addServerLifecycleListener(serverResourceListener);
serverListener = server -> {
refreshServerState();
refreshServerContent(server);
};
// add listeners to servers
for (IServer server : SonarLintCorePlugin.getServersManager().getServers()) {
server.addServerListener(serverListener);
}
}
protected void addServer(final IServer server) {
Display.getDefault().asyncExec(() -> {
tableViewer.add(tableViewer.getInput(), server);
toggleDefaultPage();
});
}
protected void removeServer(final IServer server) {
Display.getDefault().asyncExec(() -> {
tableViewer.remove(tableViewer.getInput(), new Object[] {server});
toggleDefaultPage();
});
}
@Override
public void dispose() {
SonarLintCorePlugin.getServersManager().removeServerLifecycleListener(serverResourceListener);
super.dispose();
}
}