Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce View Container and base view components #338

Open
wants to merge 7 commits into
base: taldekar/ViewRouter
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 10 additions & 40 deletions plugin/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,10 @@
id="amazonq">
</category>
<view
id="software.aws.toolkits.eclipse.amazonq.views.ReauthenticateView"
class="software.aws.toolkits.eclipse.amazonq.views.AmazonQViewContainer"
id="software.aws.toolkits.eclipse.amazonq.views.AmazonQViewContainer"
name="Amazon Q"
icon="icons/AmazonQ.png"
class="software.aws.toolkits.eclipse.amazonq.views.ReauthenticateView">
</view>
<view
id="software.aws.toolkits.eclipse.amazonq.views.DependencyMissingView"
name="Amazon Q"
icon="icons/AmazonQ.png"
class="software.aws.toolkits.eclipse.amazonq.views.DependencyMissingView">
</view>
<view
id="software.aws.toolkits.eclipse.amazonq.views.ChatAssetMissingView"
name="Amazon Q"
icon="icons/AmazonQ.png"
class="software.aws.toolkits.eclipse.amazonq.views.ChatAssetMissingView">
icon="icons/AmazonQ.png">
</view>
<view
id="software.aws.toolkits.eclipse.amazonq.views.LspStartUpFailedView"
Expand Down Expand Up @@ -107,44 +95,26 @@
<perspectiveExtension
targetID="*">
<view
id="software.aws.toolkits.eclipse.amazonq.views.ToolkitLoginWebview"
id="software.aws.toolkits.eclipse.amazonq.views.AmazonQViewContainer"
relative="org.eclipse.ui.editorss"
relationship="right"
visible="false">
</view>
<view
id="software.aws.toolkits.eclipse.amazonq.views.AmazonQChatWebview"
relative="software.aws.toolkits.eclipse.amazonq.views.ToolkitLoginWebview"
relationship="stack"
visible="false">
</view>
<view
id="software.aws.toolkits.eclipse.amazonq.views.AmazonQCodeReferenceView"
relative="software.aws.toolkits.eclipse.amazonq.views.ToolkitLoginWebview"
relationship="stack"
visible="false">
</view>
<view
id="software.aws.toolkits.eclipse.amazonq.views.DependencyMissingView"
relative="software.aws.toolkits.eclipse.amazonq.views.ToolkitLoginWebview"
id="software.aws.toolkits.eclipse.amazonq.views.ToolkitLoginWebview"
relative="software.aws.toolkits.eclipse.amazonq.views.AmazonQViewContainer"
relationship="stack"
visible="false">
</view>
<view
id="software.aws.toolkits.eclipse.amazonq.views.ReauthenticateView"
relative="software.aws.toolkits.eclipse.amazonq.views.ToolkitLoginWebview"
id="software.aws.toolkits.eclipse.amazonq.views.AmazonQChatWebview"
relative="software.aws.toolkits.eclipse.amazonq.views.AmazonQViewContainer"
relationship="stack"
visible="false">
</view>
<view
id="software.aws.toolkits.eclipse.amazonq.views.DependencyMissingView"
relative="software.aws.toolkits.eclipse.amazonq.views.ToolkitLoginWebview"
relationship="stack"
visible="false">
</view>
<view
id="software.aws.toolkits.eclipse.amazonq.views.ChatAssetMissingView"
relative="software.aws.toolkits.eclipse.amazonq.views.ToolkitLoginWebview"
id="software.aws.toolkits.eclipse.amazonq.views.AmazonQCodeReferenceView"
relative="software.aws.toolkits.eclipse.amazonq.views.AmazonQViewContainer"
relationship="stack"
visible="false">
</view>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,12 @@
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;

import software.aws.toolkits.eclipse.amazonq.lsp.manager.LspStatusManager;
import software.aws.toolkits.eclipse.amazonq.views.ViewVisibilityManager;

public class QOpenLoginViewHandler extends AbstractHandler {
@Override
public final Object execute(final ExecutionEvent event) {
if (LspStatusManager.getInstance().lspFailed()) {
ViewVisibilityManager.showLspStartUpFailedView("statusBar");
} else {
ViewVisibilityManager.showDefaultView("statusBar");
}
ViewVisibilityManager.showViewContainer("statusBar");
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
import software.aws.toolkits.eclipse.amazonq.providers.LspProviderImpl;
import software.aws.toolkits.eclipse.amazonq.telemetry.service.DefaultTelemetryService;
import software.aws.toolkits.eclipse.amazonq.telemetry.service.TelemetryService;
import software.aws.toolkits.eclipse.amazonq.util.PluginLogger;
import software.aws.toolkits.eclipse.amazonq.util.CodeReferenceLoggingService;
import software.aws.toolkits.eclipse.amazonq.util.DefaultCodeReferenceLoggingService;
import software.aws.toolkits.eclipse.amazonq.util.LoggingService;
import software.aws.toolkits.eclipse.amazonq.util.PluginLogger;

public class Activator extends AbstractUIPlugin {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.eclipse.amazonq.views;

import java.util.Map;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.part.ViewPart;

import io.reactivex.rxjava3.disposables.Disposable;
import software.aws.toolkits.eclipse.amazonq.broker.api.EventObserver;
import software.aws.toolkits.eclipse.amazonq.plugin.Activator;
import software.aws.toolkits.eclipse.amazonq.views.actions.AmazonQStaticActions;
import software.aws.toolkits.eclipse.amazonq.views.router.ViewId;


public final class AmazonQViewContainer extends ViewPart implements EventObserver<ViewId> {
private Composite parentComposite;
private StackLayout layout;
private Map<ViewId, BaseAmazonQView> views;
private ViewId activeId;
private BaseAmazonQView activeView;
private Disposable viewChangeEventSubscription;

public AmazonQViewContainer() {
viewChangeEventSubscription = Activator.getEventBroker().subscribe(ViewId.class, this);
}

/* Router should be initialized, then init view container
* ViewRouter.Initialize()
* viewcontainer.init(activeViewId)
*/

/*
* When container is disposed and being reopened, class will be recreated
* need to call showView to reset viewContainer && follow up with init call to container
* 1. showView(viewContainer.ID)
* 2. viewContainer.init(currentView)
*/

public void initializeViews(final ViewId currentActiveViewId) {

//init map containing all views
var dependencyMissingView = new DependencyMissingView();
var chatAssetMissingView = new ChatAssetMissingView();
var reAuthView = new ReauthenticateView();
var lspFailedView = new LspStartUpFailedView();
views = Map.of(
ViewId.CHAT_ASSET_MISSING_VIEW, chatAssetMissingView,
ViewId.DEPENDENCY_MISSING_VIEW, dependencyMissingView,
ViewId.RE_AUTHENTICATE_VIEW, reAuthView,
ViewId.LSP_STARTUP_FAILED_VIEW, lspFailedView
);

//default view passed in from router
//possible we'll use chatView as default?
activeView = views.get(currentActiveViewId);
}

public void createPartControl(final Composite parent) {
parentComposite = parent;
layout = new StackLayout();
parent.setLayout(layout);

//add base stylings
GridLayout gridLayout = new GridLayout(1, false);
gridLayout.marginLeft = 20;
gridLayout.marginRight = 20;
gridLayout.marginTop = 10;
gridLayout.marginBottom = 10;
parent.setLayout(gridLayout);

setupStaticMenuActions();
updateChildView(activeView, ViewId.RE_AUTHENTICATE_VIEW);
}

/* change methodology for setupMenuActions -- move outside of viewContainer?
* will need ability to switch between the two based on which view is displaying && authState
* if viewId = static view --> new AmazonQStaticActions(getViewSite());
* if viewId = common view --> new AmazonQCommonActions(AuthState, getViewSite());
*/
private void setupStaticMenuActions() {
new AmazonQStaticActions(getViewSite());
}

private void updateChildView(final BaseAmazonQView newView, final ViewId newViewId) {
Display.getDefault().asyncExec(() -> {

if (activeView != null) {
activeView.dispose();
if (layout.topControl != null) {
layout.topControl.dispose();
}
}

Composite newViewComposite = newView.setupView(parentComposite);
GridData gridData = new GridData(SWT.CENTER, SWT.CENTER, true, true);
newViewComposite.setLayoutData(gridData);

layout.topControl = newViewComposite;
parentComposite.layout(true, true);

activeView = newView;
activeId = newViewId;
});
}

@Override
public void onEvent(final ViewId newViewId) {
if (activeId != null && activeId.equals(newViewId)) {
return;
}

if (views.containsKey(newViewId)) {
BaseAmazonQView newView = views.get(newViewId);
if (!parentComposite.isDisposed()) {
updateChildView(newView, newViewId);
}
}
}

@Override
public void setFocus() {
parentComposite.setFocus();

}

@Override
public void dispose() {
viewChangeEventSubscription.dispose();
if (activeView != null) {
activeView.dispose();
}
super.dispose();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.eclipse.amazonq.views;

import java.io.IOException;
import java.net.URL;

import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;

import software.aws.toolkits.eclipse.amazonq.plugin.Activator;
import software.aws.toolkits.eclipse.amazonq.util.PluginUtils;

public abstract class BaseAmazonQView {
public abstract Composite setupView(Composite parentComposite);
public abstract void dispose();

protected Image loadImage(final String imagePath) {
Image loadedImage = null;
try {
URL imageUrl = PluginUtils.getResource(imagePath);
if (imageUrl != null) {
loadedImage = new Image(Display.getCurrent(), imageUrl.openStream());
}
} catch (IOException e) {
Activator.getLogger().warn(e.getMessage(), e);
}
return loadedImage;
}
protected Font magnifyFontSize(final Composite parentComposite, final Font originalFont, final int fontSize) {
FontData[] fontData = originalFont.getFontData();
for (int i = 0; i < fontData.length; i++) {
fontData[i].setHeight(fontSize);
}
Font magnifiedFont = new Font(parentComposite.getDisplay(), fontData);
return magnifiedFont;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,64 @@

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
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.Label;

public abstract class CallToActionView extends BaseView {
public abstract class CallToActionView extends BaseAmazonQView {
private String buttonLabel;
private SelectionListener buttonHandler;

private final String iconPath = getIconPath();
private final String headerLabel = getHeaderLabel();
private final String detailMessage = getDetailMessage();
private Image icon;

protected abstract String getButtonLabel();
protected abstract SelectionListener getButtonHandler();
protected abstract void setupButtonFooterContent(Composite composite);

@Override
protected final void setupView() {
super.setupView();
public final Composite setupView(final Composite parentComposite) {
Composite container = new Composite(parentComposite, SWT.NONE);
GridLayout layout = new GridLayout(1, false);
layout.marginWidth = 10;
layout.marginHeight = 10;
container.setLayout(layout);

// Center the container itself
container.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));

Label iconLabel = new Label(container, SWT.NONE);
icon = loadImage(iconPath);
if (icon != null) {
iconLabel.setImage(icon);
iconLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));

iconLabel.addDisposeListener(e -> {
if (icon != null && !icon.isDisposed()) {
icon.dispose();
}
});
}

Label header = new Label(container, SWT.CENTER | SWT.WRAP);
header.setText(headerLabel);
header.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

Label detailLabel = new Label(container, SWT.CENTER | SWT.WRAP);
detailLabel.setText(detailMessage);
detailLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

this.buttonLabel = getButtonLabel();
this.buttonHandler = getButtonHandler();
setupButton(getContentComposite());
setupButtonFooterContent(getContentComposite());
setupButton(container);
setupButtonFooterContent(container);

return container;
}

private void setupButton(final Composite composite) {
Expand All @@ -45,4 +84,13 @@ protected void updateButtonStyle(final Button button) {
return;
}

@Override
public void dispose() {
// Default implementation - subclasses can override if they need to dispose of resources
}

protected abstract String getIconPath();
protected abstract String getHeaderLabel();
protected abstract String getDetailMessage();

}
Loading