IDEA-182875 Move expand/collapse icons to the tool window header

Step 1: header redesign
This commit is contained in:
Vassiliy.Kudryashov
2018-05-04 01:31:19 +03:00
parent eae2f06a12
commit 8d4a15fc1d
3 changed files with 113 additions and 406 deletions
@@ -973,18 +973,24 @@ public class ActionToolbarImpl extends JPanel implements ActionToolbar, QuickAct
@Override
protected void paintComponent(final Graphics g) {
if (getParent() == null) return;
int gap = JBUI.scale(2);
int offset = JBUI.scale(3);
int center = JBUI.scale(3);
int offset;
if (myOrientation == SwingConstants.HORIZONTAL) {
offset = ActionToolbarImpl.this.getHeight() - getMaxButtonHeight() - 1;
} else {
offset = ActionToolbarImpl.this.getWidth() - getMaxButtonWidth() - 1;
}
if (getParent() != null) {
g.setColor(UIUtil.getSeparatorColor());
if (myOrientation == SwingConstants.HORIZONTAL) {
LinePainter2D.paint((Graphics2D)g, offset, gap, offset, getParent().getSize().height - gap * 2 - offset);
LinePainter2D.paint((Graphics2D)g, center, gap, center, ActionToolbarImpl.this.getHeight() - gap * 2 - offset);
}
else {
LinePainter2D.paint((Graphics2D)g, gap, offset, getParent().getSize().width - gap * 2 - offset, offset);
LinePainter2D.paint((Graphics2D)g, gap, center, ActionToolbarImpl.this.getWidth() - gap * 2 - offset, center);
}
}
}
}
@@ -3,6 +3,7 @@
*/
package com.intellij.openapi.wm.impl;
import com.intellij.icons.AllIcons;
import com.intellij.ide.actions.ContextHelpAction;
import com.intellij.ide.actions.ResizeToolWindowAction;
import com.intellij.ide.actions.ToggleToolbarAction;
@@ -93,9 +94,7 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr
setFocusable(false);
setFocusTraversalPolicy(new LayoutFocusTraversalPolicy());
myHeader = new ToolWindowHeader(toolWindow, info, () -> {
return /*createGearPopupGroup()*/createPopupGroup(true);
}) {
myHeader = new ToolWindowHeader(toolWindow, () -> createPopupGroup(true)) {
@Override
protected boolean isActive() {
return myToolWindow.isActive();
@@ -382,6 +381,9 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr
public final ActionGroup createPopupGroup(boolean skipHideAction) {
final DefaultActionGroup group = createGearPopupGroup();
if (myInfo == null) {
return group;
}
if (!ToolWindowId.PREVIEW.equals(myInfo.getId())) {
group.add(myToggleContentUiTypeAction);
}
@@ -446,39 +448,46 @@ public final class InternalDecorator extends JPanel implements Queryable, DataPr
}
private DefaultActionGroup createGearPopupGroup() {
final DefaultActionGroup group = new DefaultActionGroup();
return new GearActionGroup();
}
if (myAdditionalGearActions != null) {
addSorted(group, myAdditionalGearActions);
group.addSeparator();
}
group.addAction(myToggleToolbarGroup).setAsSecondary(true);
if (myInfo.isDocked()) {
group.add(myToggleAutoHideModeAction);
group.add(myToggleDockModeAction);
group.add(myToggleFloatingModeAction);
group.add(myToggleWindowedModeAction);
group.add(myToggleSideModeAction);
}
else if (myInfo.isFloating()) {
group.add(myToggleAutoHideModeAction);
group.add(myToggleFloatingModeAction);
group.add(myToggleWindowedModeAction);
}
else if (myInfo.isWindowed()) {
group.add(myToggleFloatingModeAction);
group.add(myToggleWindowedModeAction);
}
else if (myInfo.isSliding()) {
if (!ToolWindowId.PREVIEW.equals(myInfo.getId())) {
group.add(myToggleDockModeAction);
private class GearActionGroup extends DefaultActionGroup {
public GearActionGroup() {
getTemplatePresentation().setIcon(AllIcons.General.GearPlain);
getTemplatePresentation().setText("Show Options Menu");
if (myInfo == null) return;
if (myAdditionalGearActions != null) {
addSorted(this, myAdditionalGearActions);
addSeparator();
}
group.add(myToggleFloatingModeAction);
group.add(myToggleWindowedModeAction);
group.add(myToggleSideModeAction);
addAction(myToggleToolbarGroup).setAsSecondary(true);
if (myInfo.isDocked()) {
add(myToggleAutoHideModeAction);
add(myToggleDockModeAction);
add(myToggleFloatingModeAction);
add(myToggleWindowedModeAction);
add(myToggleSideModeAction);
}
else if (myInfo.isFloating()) {
add(myToggleAutoHideModeAction);
add(myToggleFloatingModeAction);
add(myToggleWindowedModeAction);
}
else if (myInfo.isWindowed()) {
add(myToggleFloatingModeAction);
add(myToggleWindowedModeAction);
}
else if (myInfo.isSliding()) {
if (!ToolWindowId.PREVIEW.equals(myInfo.getId())) {
add(myToggleDockModeAction);
}
add(myToggleFloatingModeAction);
add(myToggleWindowedModeAction);
add(myToggleSideModeAction);
}
add(myHideStripeButtonAction);
}
group.add(myHideStripeButtonAction);
return group;
}
private static void addSorted(DefaultActionGroup main, ActionGroup group) {
@@ -2,77 +2,67 @@
package com.intellij.openapi.wm.impl;
import com.intellij.icons.AllIcons;
import com.intellij.ide.DataManager;
import com.intellij.ide.ui.UISettings;
import com.intellij.ide.ui.UISettingsListener;
import com.intellij.internal.statistic.collectors.fus.ui.persistence.ToolbarClicksCollector;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
import com.intellij.openapi.actionSystem.impl.*;
import com.intellij.openapi.application.impl.LaterInvocator;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.actionSystem.impl.ActionManagerImpl;
import com.intellij.openapi.actionSystem.impl.MenuItemPresentationFactory;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowAnchor;
import com.intellij.openapi.wm.ToolWindowType;
import com.intellij.openapi.wm.impl.content.ToolWindowContentUi;
import com.intellij.ui.DoubleClickListener;
import com.intellij.ui.InplaceButton;
import com.intellij.ui.PopupHandler;
import com.intellij.ui.UIBundle;
import com.intellij.ui.components.panels.Wrapper;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.ui.tabs.TabsUtil;
import com.intellij.util.BitUtil;
import com.intellij.util.Producer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.EmptyIcon;
import com.intellij.util.ui.JBSwingUtilities;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.accessibility.AccessibleContextUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.plaf.PanelUI;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeListener;
import java.util.List;
/**
* @author pegov
*/
public abstract class ToolWindowHeader extends JPanel implements Disposable, UISettingsListener {
@NonNls private static final String HIDE_ACTIVE_WINDOW_ACTION_ID = "HideActiveWindow";
@NonNls private static final String HIDE_ACTIVE_SIDE_WINDOW_ACTION_ID = "HideSideWindows";
@NotNull private final Producer<ActionGroup> myGearProducer;
private ToolWindow myToolWindow;
private WindowInfoImpl myInfo;
private final ToolWindowHeader.ActionButton myHideButton;
private BufferedImage myImage;
private BufferedImage myActiveImage;
private ToolWindowType myImageType;
private final JPanel myButtonPanel;
private final ToolWindowHeader.ActionButton myGearButton;
private final PresentationFactory myPresentationFactory = new PresentationFactory();
private final ToolbarUpdater myUpdater;
private final DefaultActionGroup myActionGroup = new DefaultActionGroup();
private List<AnAction> myVisibleActions = ContainerUtil.newArrayListWithCapacity(2);
private ActionToolbar myToolbar;
/**
* @deprecated
* @param info won't be used anymore
*/
ToolWindowHeader(final ToolWindowImpl toolWindow, @NotNull WindowInfoImpl info, @NotNull final Producer<ActionGroup> gearProducer) {
this(toolWindow, gearProducer);
}
ToolWindowHeader(final ToolWindowImpl toolWindow, @NotNull final Producer<ActionGroup> gearProducer) {
myGearProducer = gearProducer;
setLayout(new BorderLayout());
AccessibleContextUtil.setName(this, "Tool Window Header");
myToolWindow = toolWindow;
myInfo = info;
JPanel westPanel = new JPanel() {
JPanel westPanel = new NonOpaquePanel() {
@Override
public void doLayout() {
if (getComponentCount() > 0) {
@@ -90,76 +80,23 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS
}
};
westPanel.setOpaque(false);
add(westPanel, BorderLayout.CENTER);
westPanel.add(toolWindow.getContentUI().getTabComponent());
ToolWindowContentUi.initMouseListeners(westPanel, toolWindow.getContentUI(), true);
JPanel eastPanel = new JPanel();
eastPanel.setOpaque(false);
eastPanel.setLayout(new BoxLayout(eastPanel, BoxLayout.X_AXIS));
eastPanel.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 3));
add(eastPanel, BorderLayout.EAST);
myGearButton = new ActionButton(new DumbAwareAction("Show Options menu") {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
final InputEvent inputEvent = e.getInputEvent();
final ActionPopupMenu popupMenu =
((ActionManagerImpl)ActionManager.getInstance())
.createActionPopupMenu(ToolWindowContentUi.POPUP_PLACE, gearProducer.produce(), new MenuItemPresentationFactory(true));
int x = 0;
int y = 0;
if (inputEvent instanceof MouseEvent) {
x = ((MouseEvent)inputEvent).getX();
y = ((MouseEvent)inputEvent).getY();
}
ToolbarClicksCollector.record("Show Options", "ToolWindowHeader");
popupMenu.getComponent().show(inputEvent.getComponent(), x, y);
}
}, AllIcons.General.Gear) {
@Override
protected Icon getActiveHoveredIcon() {
return AllIcons.General.GearHover;
}
};
myHideButton = new ActionButton(new HideAction() {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
hideToolWindow();
}
}, new HideSideAction() {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
sideHidden();
}
}, AllIcons.General.HideLeft, null, null) {
@Override
protected Icon getActiveIcon() {
return getHideToolWindowIcon(myToolWindow);
}
@Override
protected Icon getAlternativeIcon() {
return getHideIcon(myToolWindow);
}
@Override
protected Icon getActiveHoveredIcon() {
return getHideToolWindowHoveredIcon(myToolWindow);
}
@Override
protected Icon getAlternativeHoveredIcon() {
return getHideHoveredIcon(myToolWindow);
}
};
addDefaultActions(eastPanel);
myButtonPanel = eastPanel;
myToolbar = ActionManager.getInstance().createActionToolbar(
ActionPlaces.TOOLWINDOW_TITLE,
new DefaultActionGroup(myActionGroup, new ShowOptionsAction(), new HideAction()),
true);
myToolbar.setTargetComponent(this);
myToolbar.setLayoutPolicy(ActionToolbar.NOWRAP_LAYOUT_POLICY);
myToolbar.setReservePlaceAutoPopupIcon(false);
JComponent component = myToolbar.getComponent();
component.setBorder(JBUI.Borders.empty());
component.setOpaque(false);
add(component, BorderLayout.EAST);
westPanel.addMouseListener(new PopupHandler() {
@Override
@@ -196,19 +133,6 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS
setOpaque(true);
setBorder(BorderFactory.createEmptyBorder(TabsUtil.TABS_BORDER, 1, TabsUtil.TABS_BORDER, 1));
myUpdater = new ToolbarUpdater(this) {
@Override
protected void updateActionsImpl(boolean transparentOnly, boolean forced) {
ToolWindowHeader.this.updateActionsImpl(transparentOnly, forced);
}
@Override
protected void updateActionTooltips() {
for (ActionButton actionButton : UIUtil.uiTraverser(myButtonPanel).preOrderDfsTraversal().filter(ActionButton.class)) {
actionButton.updateTooltip();
}
}
};
new DoubleClickListener(){
@Override
protected boolean onDoubleClick(MouseEvent event) {
@@ -233,108 +157,21 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS
clearCaches();
}
private void addDefaultActions(JPanel eastPanel) {
eastPanel.add(myGearButton);
eastPanel.add(Box.createHorizontalStrut(6));
eastPanel.add(myHideButton);
eastPanel.add(Box.createHorizontalStrut(1));
}
@Override
public void dispose() {
removeAll();
myToolWindow = null;
myInfo = null;
}
void setAdditionalTitleActions(AnAction[] actions) {
myActionGroup.removeAll();
myActionGroup.addAll(actions);
myUpdater.updateActions(false, true);
}
private void updateActionsImpl(boolean transparentOnly, boolean forced) {
List<AnAction> newVisibleActions = ContainerUtil.newArrayListWithCapacity(myVisibleActions.size());
DataContext dataContext = DataManager.getInstance().getDataContext(this);
Utils.expandActionGroup(LaterInvocator.isInModalContext(), myActionGroup, newVisibleActions, myPresentationFactory, dataContext,
ActionPlaces.TOOLWINDOW_TITLE, myUpdater.getActionManager(), transparentOnly);
if (forced || !newVisibleActions.equals(myVisibleActions)) {
myVisibleActions = newVisibleActions;
myButtonPanel.removeAll();
boolean actionAdded = false;
for (final AnAction action : newVisibleActions) {
if (action == null) continue;
final Presentation presentation = myPresentationFactory.getPresentation(action);
myButtonPanel.add(new ActionButton(action, presentation.getIcon()) {
@Override
protected Icon getActiveHoveredIcon() {
Icon icon = presentation.getHoveredIcon();
return icon != null ? icon : super.getActiveHoveredIcon();
}
});
myButtonPanel.add(Box.createHorizontalStrut(9));
actionAdded = true;
}
if (actionAdded) {
myButtonPanel.add(new JLabel(AllIcons.General.Divider));
myButtonPanel.add(Box.createHorizontalStrut(6));
}
addDefaultActions(myButtonPanel);
revalidate();
repaint();
if (actions.length > 0) {
myActionGroup.addSeparator();
}
}
private static Icon getHideToolWindowIcon(ToolWindow toolWindow) {
ToolWindowAnchor anchor = toolWindow.getAnchor();
if (anchor == ToolWindowAnchor.BOTTOM) {
return AllIcons.General.HideDownPart;
if (myToolbar != null) {
myToolbar.updateActionsImmediately();
}
if (anchor == ToolWindowAnchor.RIGHT) {
return AllIcons.General.HideRightPart;
}
return AllIcons.General.HideLeftPart;
}
private static Icon getHideIcon(ToolWindow toolWindow) {
ToolWindowAnchor anchor = toolWindow.getAnchor();
if (anchor == ToolWindowAnchor.BOTTOM) {
return AllIcons.General.HideDown;
}
if (anchor == ToolWindowAnchor.RIGHT) {
return AllIcons.General.HideRight;
}
return AllIcons.General.HideLeft;
}
private static Icon getHideToolWindowHoveredIcon(ToolWindow toolWindow) {
ToolWindowAnchor anchor = toolWindow.getAnchor();
if (anchor == ToolWindowAnchor.BOTTOM) {
return AllIcons.General.HideDownPartHover;
}
if (anchor == ToolWindowAnchor.RIGHT) {
return AllIcons.General.HideRightPartHover;
}
return AllIcons.General.HideLeftPartHover;
}
private static Icon getHideHoveredIcon(ToolWindow toolWindow) {
ToolWindowAnchor anchor = toolWindow.getAnchor();
if (anchor == ToolWindowAnchor.BOTTOM) {
return AllIcons.General.HideDownHover;
}
if (anchor == ToolWindowAnchor.RIGHT) {
return AllIcons.General.HideRightHover;
}
return AllIcons.General.HideLeftHover;
}
@Override
@@ -432,189 +269,44 @@ public abstract class ToolWindowHeader extends JPanel implements Disposable, UIS
return new Dimension(size.width, TabsUtil.getTabsHeight(JBUI.CurrentTheme.ToolWindow.tabVerticalPadding()));
}
private class ActionButton extends Wrapper implements ActionListener, AltStateManager.AltListener {
private final InplaceButton myButton;
private final AnAction myAction;
private final AnAction myAlternativeAction;
private final Icon myActiveIcon;
private final Icon myInactiveIcon;
private final Icon myAlternativeIcon;
private AnAction myCurrentAction;
public ActionButton(AnAction action, AnAction alternativeAction, @NotNull Icon activeIcon, Icon inactiveIcon,
Icon alternativeIcon) {
myAction = action;
myAlternativeAction = alternativeAction;
myActiveIcon = activeIcon;
myInactiveIcon = inactiveIcon;
myAlternativeIcon = alternativeIcon;
myCurrentAction = myAction;
myButton = new InplaceButton(getToolTipTextByAction(action),
EmptyIcon.ICON_16, this) {
@Override
public boolean isActive() {
return ActionButton.this.isActive();
}
};
myButton.setHoveringEnabled(!SystemInfo.isMac);
setContent(myButton);
setOpaque(false);
setIcon(getActiveIcon(), getInactiveIcon() == null ? getActiveIcon() : getInactiveIcon(), getActiveHoveredIcon());
PropertyChangeListener listener = evt -> {
if (myAlternativeAction == null) return;
if ("ancestor".equals(evt.getPropertyName())) {
if (evt.getNewValue() == null) {
AltStateManager.getInstance().removeListener(this);
switchAlternativeAction(false);
}
else {
AltStateManager.getInstance().addListener(this);
}
}
};
addPropertyChangeListener(listener);
}
void updateTooltip() {
myButton.setToolTipText(getToolTipTextByAction(myCurrentAction));
}
protected Icon getActiveIcon() {
return myActiveIcon;
}
protected Icon getActiveHoveredIcon() {
return myActiveIcon;
}
protected Icon getInactiveIcon() {
return myInactiveIcon;
}
protected Icon getAlternativeIcon() {
return myAlternativeIcon;
}
protected Icon getAlternativeHoveredIcon() {
return myAlternativeIcon;
}
private void switchAlternativeAction(boolean b) {
if (b && myCurrentAction == myAlternativeAction) return;
if (!b && myCurrentAction != myAlternativeAction) return;
setIcon(b ? getAlternativeIcon() : getActiveIcon(),
b ? getAlternativeIcon() : getInactiveIcon() == null ? getActiveIcon() : getInactiveIcon(),
b ? getAlternativeHoveredIcon() : getActiveHoveredIcon());
myCurrentAction = b ? myAlternativeAction : myAction;
setToolTipText(getToolTipTextByAction(myCurrentAction));
repaint();
}
public ActionButton(AnAction action, @NotNull Icon activeIcon, Icon inactiveIcon) {
this(action, null, activeIcon, inactiveIcon, null);
}
public ActionButton(AnAction action, Icon activeIcon) {
this(action, activeIcon, activeIcon);
private class ShowOptionsAction extends DumbAwareAction {
ShowOptionsAction() {
copyFrom(myGearProducer.produce());
}
@Override
public void actionPerformed(final ActionEvent e) {
AnAction action =
myAlternativeAction != null && BitUtil.isSet(e.getModifiers(), InputEvent.ALT_MASK) ? myAlternativeAction : myAction;
final DataContext dataContext = DataManager.getInstance().getDataContext(this);
final ActionManagerEx actionManager = ActionManagerEx.getInstanceEx();
InputEvent inputEvent = e.getSource() instanceof InputEvent ? (InputEvent) e.getSource() : null;
final AnActionEvent event = AnActionEvent.createFromAnAction(action, inputEvent, ActionPlaces.TOOLWINDOW_TITLE, dataContext);
actionManager.fireBeforeActionPerformed(action, dataContext, event);
final Component component = PlatformDataKeys.CONTEXT_COMPONENT.getData(dataContext);
if (component != null && !component.isShowing()) {
return;
public void actionPerformed(@NotNull AnActionEvent e) {
final InputEvent inputEvent = e.getInputEvent();
final ActionPopupMenu popupMenu =
((ActionManagerImpl)ActionManager.getInstance())
.createActionPopupMenu(ToolWindowContentUi.POPUP_PLACE, myGearProducer.produce(), new MenuItemPresentationFactory(true));
int x = 0;
int y = 0;
if (inputEvent instanceof MouseEvent) {
x = ((MouseEvent)inputEvent).getX();
y = ((MouseEvent)inputEvent).getY();
}
action.actionPerformed(event);
}
public boolean isActive() {
return ToolWindowHeader.this.isActive();
}
public void setIcon(final Icon active, Icon inactive, Icon hovered) {
myButton.setIcons(active, inactive, hovered);
}
@Override
public void setToolTipText(final String text) {
myButton.setToolTipText(text);
}
@Override
public void altPressed() {
PointerInfo info = MouseInfo.getPointerInfo();
if (info != null) {
Point p = info.getLocation();
SwingUtilities.convertPointFromScreen(p, this);
switchAlternativeAction(myButton.getBounds().contains(p));
}
}
@Override
public void altReleased() {
switchAlternativeAction(false);
ToolbarClicksCollector.record("Show Options", "ToolWindowHeader");
popupMenu.getComponent().show(inputEvent.getComponent(), x, y);
}
}
private static String getToolTipTextByAction(AnAction action) {
String text = KeymapUtil.createTooltipText(action.getTemplatePresentation().getText(), action);
if (action instanceof HideAction) {
text += String.format(" (Click with %s to Hide Side)", KeymapUtil.getShortcutText(KeyboardShortcut.fromString("pressed ALT")));
}
return text;
}
private abstract class HideSideAction extends AnAction implements DumbAware {
@NonNls static final String HIDE_ACTIVE_SIDE_WINDOW_ACTION_ID = ToolWindowHeader.HIDE_ACTIVE_SIDE_WINDOW_ACTION_ID;
public HideSideAction() {
copyFrom(ActionManager.getInstance().getAction(HIDE_ACTIVE_SIDE_WINDOW_ACTION_ID));
getTemplatePresentation().setText(UIBundle.message("tool.window.hideSide.action.name"));
}
@Override
public abstract void actionPerformed(@NotNull final AnActionEvent e);
@Override
public final void update(@NotNull final AnActionEvent event) {
final Presentation presentation = event.getPresentation();
presentation.setEnabled(myInfo.isVisible());
}
}
private abstract class HideAction extends AnAction implements DumbAware {
@NonNls static final String HIDE_ACTIVE_WINDOW_ACTION_ID = ToolWindowHeader.HIDE_ACTIVE_WINDOW_ACTION_ID;
private class HideAction extends DumbAwareAction {
public HideAction() {
copyFrom(ActionManager.getInstance().getAction(HIDE_ACTIVE_WINDOW_ACTION_ID));
copyFrom(ActionManager.getInstance().getAction(InternalDecorator.HIDE_ACTIVE_WINDOW_ACTION_ID));
getTemplatePresentation().setIcon(AllIcons.General.HideToolWindow);
getTemplatePresentation().setText(UIBundle.message("tool.window.hide.action.name"));
}
@Override
public void actionPerformed(AnActionEvent e) {
hideToolWindow();
}
@Override
public final void update(@NotNull final AnActionEvent event) {
final Presentation presentation = event.getPresentation();
presentation.setEnabled(myInfo.isVisible());
event.getPresentation().setEnabled(myToolWindow.isVisible());
}
}
}