Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ public void completed(final ProgressEvent event) {
}
browser.setText(content.get());

setupAmazonQCommonActions();

return parent;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,15 @@
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IViewSite;

import io.reactivex.rxjava3.disposables.Disposable;
import software.aws.toolkits.eclipse.amazonq.lsp.auth.model.AuthState;
import software.aws.toolkits.eclipse.amazonq.plugin.Activator;
import software.aws.toolkits.eclipse.amazonq.providers.browser.AmazonQBrowserProvider;
import software.aws.toolkits.eclipse.amazonq.util.ThemeDetector;
import software.aws.toolkits.eclipse.amazonq.views.actions.AmazonQCommonActions;

public abstract class AmazonQView extends BaseAmazonQView {

private AmazonQBrowserProvider browserProvider;
private AmazonQCommonActions amazonQCommonActions;
private static final ThemeDetector THEME_DETECTOR = new ThemeDetector();

private Disposable signOutActionAuthStateSubscription;
private Disposable feedbackDialogAuthStateSubscription;
private Disposable customizationDialogAuthStateSubscription;
private Disposable toggleAutoTriggerAuthStateSubscription;

private IViewSite viewSite;

protected AmazonQView() {
this.browserProvider = new AmazonQBrowserProvider();
}
Expand All @@ -39,10 +26,6 @@ public final Browser getBrowser() {
return browserProvider.getBrowser();
}

public final AmazonQCommonActions getAmazonQCommonActions() {
return amazonQCommonActions;
}

protected final void setupParentBackground(final Composite parent) {
Display display = Display.getCurrent();
Color bg = THEME_DETECTOR.isDarkTheme() ? display.getSystemColor(SWT.COLOR_BLACK)
Expand Down Expand Up @@ -77,8 +60,6 @@ public Composite setupView(final Composite parent) {

if (browser != null && !browser.isDisposed()) {
setupBrowserBackground(parent);
setupActions();
setupAuthStatusListeners();
disableBrowserContextMenu();
}

Expand All @@ -94,25 +75,6 @@ private void setupBrowserBackground(final Composite parent) {
getBrowser().setBackground(bgColor);
}

private void setupActions() {
amazonQCommonActions = new AmazonQCommonActions(viewSite);
}

private void setupAuthStatusListeners() {
signOutActionAuthStateSubscription = Activator.getEventBroker().subscribe(AuthState.class,
amazonQCommonActions.getSignoutAction());
feedbackDialogAuthStateSubscription = Activator.getEventBroker().subscribe(AuthState.class,
amazonQCommonActions.getFeedbackDialogContributionAction());
customizationDialogAuthStateSubscription = Activator.getEventBroker().subscribe(AuthState.class,
amazonQCommonActions.getCustomizationDialogContributionAction());
toggleAutoTriggerAuthStateSubscription = Activator.getEventBroker().subscribe(AuthState.class,
amazonQCommonActions.getToggleAutoTriggerContributionAction());
}

public final void setViewSite(final IViewSite viewSite) {
this.viewSite = viewSite;
}

public final void addFocusListener(final Composite parent, final Browser browser) {
parent.addFocusListener(new FocusListener() {
@Override
Expand All @@ -137,19 +99,7 @@ public void focusLost(final FocusEvent event) {
*/
@Override
public void dispose() {
if (signOutActionAuthStateSubscription != null && !signOutActionAuthStateSubscription.isDisposed()) {
signOutActionAuthStateSubscription.dispose();
}
if (feedbackDialogAuthStateSubscription != null && !feedbackDialogAuthStateSubscription.isDisposed()) {
feedbackDialogAuthStateSubscription.dispose();
}
if (customizationDialogAuthStateSubscription != null
&& !customizationDialogAuthStateSubscription.isDisposed()) {
customizationDialogAuthStateSubscription.dispose();
}
if (toggleAutoTriggerAuthStateSubscription != null && !toggleAutoTriggerAuthStateSubscription.isDisposed()) {
toggleAutoTriggerAuthStateSubscription.dispose();
}
super.dispose();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@
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.AmazonQViewType;


Expand All @@ -30,7 +28,6 @@ public final class AmazonQViewContainer extends ViewPart implements EventObserve
private Map<AmazonQViewType, BaseAmazonQView> views;
private AmazonQViewType activeViewType;
private BaseAmazonQView currentView;
private Disposable activeViewTypeSubscription;
private final ReentrantLock containerLock;

public AmazonQViewContainer() {
Expand Down Expand Up @@ -61,14 +58,9 @@ public void createPartControl(final Composite parent) {

parentComposite = parent;

setupStaticMenuActions();
updateChildView();
}

private void setupStaticMenuActions() {
new AmazonQStaticActions(getViewSite());
}

private void updateChildView() {
Display.getDefault().asyncExec(() -> {
try {
Expand All @@ -86,10 +78,7 @@ private void updateChildView() {
currentView.dispose();
}

if (activeViewType == AmazonQViewType.CHAT_VIEW
|| activeViewType == AmazonQViewType.TOOLKIT_LOGIN_VIEW) {
((AmazonQView) newView).setViewSite(getViewSite());
}
newView.setViewSite(getViewSite());

Composite newViewComposite = newView.setupView(parentComposite);
GridData gridData = new GridData(SWT.CENTER, SWT.CENTER, true, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,61 @@
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IViewSite;

import io.reactivex.rxjava3.disposables.Disposable;
import software.aws.toolkits.eclipse.amazonq.lsp.auth.model.AuthState;
import software.aws.toolkits.eclipse.amazonq.plugin.Activator;
import software.aws.toolkits.eclipse.amazonq.util.PluginUtils;
import software.aws.toolkits.eclipse.amazonq.views.actions.AmazonQCommonActions;
import software.aws.toolkits.eclipse.amazonq.views.actions.AmazonQStaticActions;

public abstract class BaseAmazonQView {

private IViewSite viewSite;

private AmazonQCommonActions amazonQCommonActions;
private AmazonQStaticActions amazonQStaticActions;

private Disposable signOutActionAuthStateSubscription;
private Disposable feedbackDialogAuthStateSubscription;
private Disposable customizationDialogAuthStateSubscription;
private Disposable toggleAutoTriggerAuthStateSubscription;

public abstract Composite setupView(Composite parentComposite);
public abstract void dispose();

public final void setViewSite(final IViewSite viewSite) {
this.viewSite = viewSite;
}

protected final void setupAmazonQCommonActions() {
if (viewSite == null) {
Activator.getLogger().info("View Site is null for creating AmazonQCommonActions");
return;
}

amazonQCommonActions = new AmazonQCommonActions(viewSite);
setupCommonActionAuthListeners();
viewSite.getActionBars().updateActionBars();
}

protected final void setupAmazonQStaticActions() {
if (viewSite == null) {
Activator.getLogger().info("View Site is null for creating AmazonQStaticActions");
return;
}

amazonQStaticActions = new AmazonQStaticActions(viewSite);
viewSite.getActionBars().updateActionBars();
}

protected final AmazonQCommonActions getAmazonQCommonActions() {
return amazonQCommonActions;
}

protected final AmazonQStaticActions getAmazonQStaticActions() {
return amazonQStaticActions;
}

protected final Image loadImage(final String imagePath) {
Image loadedImage = null;
Expand All @@ -40,4 +88,62 @@ protected final Font magnifyFontSize(final Composite parentComposite, final Font
Font magnifiedFont = new Font(parentComposite.getDisplay(), fontData);
return magnifiedFont;
}

private void setupCommonActionAuthListeners() {
signOutActionAuthStateSubscription = Activator.getEventBroker().subscribe(AuthState.class,
amazonQCommonActions.getSignoutAction());
feedbackDialogAuthStateSubscription = Activator.getEventBroker().subscribe(AuthState.class,
amazonQCommonActions.getFeedbackDialogContributionAction());
customizationDialogAuthStateSubscription = Activator.getEventBroker().subscribe(AuthState.class,
amazonQCommonActions.getCustomizationDialogContributionAction());
toggleAutoTriggerAuthStateSubscription = Activator.getEventBroker().subscribe(AuthState.class,
amazonQCommonActions.getToggleAutoTriggerContributionAction());
}

/**
* Disposes of resources and cleans up subscriptions when the view is closed.
* This method ensures proper cleanup of authentication state subscriptions to prevent memory leaks.
*
* The following subscriptions are disposed:
* - Sign out action authentication state
* - Feedback dialog authentication state
* - Customization dialog authentication state
* - Auto-trigger toggle authentication state
*
* Each subscription is checked for null and disposal state before being disposed
* to prevent potential null pointer exceptions.
*/
public void dispose() {
if (amazonQCommonActions != null) {
amazonQCommonActions.dispose();
amazonQCommonActions = null;
}

if (amazonQStaticActions != null) {
amazonQStaticActions.dispose();
amazonQStaticActions = null;
}

if (signOutActionAuthStateSubscription != null && !signOutActionAuthStateSubscription.isDisposed()) {
signOutActionAuthStateSubscription.dispose();
signOutActionAuthStateSubscription = null;
}

if (feedbackDialogAuthStateSubscription != null && !feedbackDialogAuthStateSubscription.isDisposed()) {
feedbackDialogAuthStateSubscription.dispose();
feedbackDialogAuthStateSubscription = null;
}

if (customizationDialogAuthStateSubscription != null
&& !customizationDialogAuthStateSubscription.isDisposed()) {
customizationDialogAuthStateSubscription.dispose();
customizationDialogAuthStateSubscription = null;
}

if (toggleAutoTriggerAuthStateSubscription != null && !toggleAutoTriggerAuthStateSubscription.isDisposed()) {
toggleAutoTriggerAuthStateSubscription.dispose();
toggleAutoTriggerAuthStateSubscription = null;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ public final Composite setupView(final Composite parentComposite) {
setupButton(container);
setupButtonFooterContent(container);

setupAmazonQStaticActions();

return container;
}

Expand All @@ -85,8 +87,8 @@ protected void updateButtonStyle(final Button button) {
}

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

protected abstract String getIconPath();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,16 @@
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import software.aws.toolkits.eclipse.amazonq.util.ChatAssetProvider;

public final class ChatAssetMissingView extends BaseAmazonQView {
public static final String ID = "software.aws.toolkits.eclipse.amazonq.views.ChatAssetMissingView";

private static final String ICON_PATH = "icons/AmazonQ64.png";
private static final String HEADER_LABEL = "Error loading Q chat.";
private static final String DETAIL_MESSAGE = "Restart Eclipse or review error logs for troubleshooting";
private ChatAssetProvider chatAssetProvider;
private Image icon;
private Composite container;

public ChatAssetMissingView() {
this.chatAssetProvider = new ChatAssetProvider();
}

@Override
public Composite setupView(final Composite parentComposite) {
container = new Composite(parentComposite, SWT.NONE);
Expand Down Expand Up @@ -62,14 +56,13 @@ public Composite setupView(final Composite parentComposite) {
detailLabel.setText(DETAIL_MESSAGE);
detailLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

setupAmazonQStaticActions();

return container;
}

@Override
public void dispose() {
if (chatAssetProvider != null) {
chatAssetProvider.dispose();
chatAssetProvider = null;
}
super.dispose();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ protected void setupButtonFooterContent(final Composite composite) {

private String getInstallUrl() {
return platform == PluginPlatform.WINDOWS ? EDGE_INSTALL : WEBKIT_INSTALL;

}

private String getLearnMoreUrl() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ public final class LspStartUpFailedView extends BaseAmazonQView {
private Image icon;
private Composite container;

public LspStartUpFailedView() {
//
}

@Override
public Composite setupView(final Composite parentComposite) {
container = new Composite(parentComposite, SWT.NONE);
Expand Down Expand Up @@ -62,12 +58,14 @@ public Composite setupView(final Composite parentComposite) {
detailLabel.setText(DETAIL_MESSAGE);
detailLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

setupAmazonQStaticActions();

return container;
}

@Override
public void dispose() {
//default implementation
super.dispose();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ public Object function(final Object[] arguments) {

browser.setText(content.get());

setupAmazonQCommonActions();

return parent;
}

Expand Down
Loading