All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.intellij.openapi.wm.impl.IdeFrameImpl Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition platform-impl library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * Copyright 2000-2014 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.openapi.wm.impl;

import com.intellij.diagnostic.IdeMessagePanel;
import com.intellij.ide.AppLifecycleListener;
import com.intellij.ide.DataManager;
import com.intellij.ide.impl.ProjectUtil;
import com.intellij.ide.ui.UISettings;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.notification.impl.IdeNotificationArea;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.MnemonicHelper;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
import com.intellij.openapi.actionSystem.impl.MouseGestureManager;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.ex.ApplicationInfoEx;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.IdeRootPaneNorthExtension;
import com.intellij.openapi.wm.StatusBar;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.ex.IdeFrameEx;
import com.intellij.openapi.wm.ex.LayoutFocusTraversalPolicyExt;
import com.intellij.openapi.wm.ex.StatusBarEx;
import com.intellij.openapi.wm.impl.status.*;
import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeFrame;
import com.intellij.ui.*;
import com.intellij.ui.mac.MacMainFrameDecorator;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.io.PowerSupplyKit;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;

/**
 * @author Anton Katilin
 * @author Vladimir Kondratyev
 */
public class IdeFrameImpl extends JFrame implements IdeFrameEx, DataProvider {
  public static final Key SHOULD_OPEN_IN_FULL_SCREEN = Key.create("should.open.in.full.screen");

  private static final String FULL_SCREEN = "FullScreen";

  private static boolean myUpdatingTitle;

  private String myTitle;
  private String myFileTitle;
  private File myCurrentFile;

  private Project myProject;

  private IdeRootPane myRootPane;
  private final BalloonLayout myBalloonLayout;
  private IdeFrameDecorator myFrameDecorator;
  private PropertyChangeListener myWindowsBorderUpdater = null;
  private boolean myRestoreFullScreen;

  public IdeFrameImpl(ApplicationInfoEx applicationInfoEx,
                      ActionManagerEx actionManager,
                      DataManager dataManager,
                      Application application) {
    super(applicationInfoEx.getFullApplicationName());
    myRootPane = createRootPane(actionManager, UISettings.getInstance(), dataManager, application);
    setRootPane(myRootPane);
    setBackground(UIUtil.getPanelBackground());
    AppUIUtil.updateWindowIcon(this);
    final Dimension size = ScreenUtil.getMainScreenBounds().getSize();

    size.width = Math.min(1400, size.width - 20);
    size.height= Math.min(1000, size.height - 40);

    setSize(size);
    setLocationRelativeTo(null);

    LayoutFocusTraversalPolicyExt layoutFocusTraversalPolicy = new LayoutFocusTraversalPolicyExt();
    setFocusTraversalPolicy(layoutFocusTraversalPolicy);

    setupCloseAction();
    MnemonicHelper.init(this);

    myBalloonLayout = new BalloonLayoutImpl(myRootPane, new Insets(8, 8, 8, 8));

    // to show window thumbnail under Macs
    // http://lists.apple.com/archives/java-dev/2009/Dec/msg00240.html
    if (SystemInfo.isMac) setIconImage(null);

    MouseGestureManager.getInstance().add(this);

    myFrameDecorator = IdeFrameDecorator.decorate(this);

    addWindowStateListener(new WindowAdapter() {
      @Override
      public void windowStateChanged(WindowEvent e) {
        updateBorder();
      }
    });
    if (SystemInfo.isWindows) {
      myWindowsBorderUpdater = new PropertyChangeListener() {
        @Override
        public void propertyChange(@NotNull PropertyChangeEvent evt) {
          updateBorder();
        }
      };
      Toolkit.getDefaultToolkit().addPropertyChangeListener("win.xpstyle.themeActive", myWindowsBorderUpdater);
    }

    IdeMenuBar.installAppMenuIfNeeded(this);

    // UIUtil.suppressFocusStealing();

  }

  @Override
  public void addNotify() {
    super.addNotify();
    PowerSupplyKit.checkPowerSupply();
  }



  private void updateBorder() {
    int state = getExtendedState();
    if (!WindowManager.getInstance().isFullScreenSupportedInCurrentOS() || !SystemInfo.isWindows || myRootPane == null) {
      return;
    }

    myRootPane.setBorder(null);
    boolean isNotClassic = Boolean.parseBoolean(String.valueOf(Toolkit.getDefaultToolkit().getDesktopProperty("win.xpstyle.themeActive")));
    if (isNotClassic && (state & MAXIMIZED_BOTH) != 0) {
      IdeFrame[] projectFrames = WindowManager.getInstance().getAllProjectFrames();
      GraphicsDevice device = ScreenUtil.getScreenDevice(getBounds());

      for (IdeFrame frame : projectFrames) {
        if (frame == this) continue;
        if (((IdeFrameImpl)frame).isInFullScreen() && ScreenUtil.getScreenDevice(((IdeFrameImpl)frame).getBounds()) == device) {
          Insets insets = ScreenUtil.getScreenInsets(device.getDefaultConfiguration());
          int mask = SideBorder.NONE;
          if (insets.top != 0) mask |= SideBorder.TOP;
          if (insets.left != 0) mask |= SideBorder.LEFT;
          if (insets.bottom != 0) mask |= SideBorder.BOTTOM;
          if (insets.right != 0) mask |= SideBorder.RIGHT;
          myRootPane.setBorder(new SideBorder(JBColor.BLACK, mask, 3));
          break;
        }
      }
    }
  }

  protected IdeRootPane createRootPane(ActionManagerEx actionManager,
                                       UISettings uiSettings,
                                       DataManager dataManager,
                                       Application application) {
    return new IdeRootPane(actionManager, uiSettings, dataManager, application, this);
  }

  @NotNull
  @Override
  public Insets getInsets() {
    if (SystemInfo.isMac && isInFullScreen()) {
      return new Insets(0, 0, 0, 0);
    }
    return super.getInsets();
  }

  @Override
  public JComponent getComponent() {
    return getRootPane();
  }

  @Nullable
  public static Window getActiveFrame() {
    for (Frame frame : getFrames()) {
      if (frame.isActive()) return frame;
    }
    return null;
  }

  @SuppressWarnings({"deprecation", "SSBasedInspection"})
  @Override
  public void show() {
    super.show();
    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        setFocusableWindowState(true);
      }
    });
  }

  /**
   * This is overridden to get rid of strange Alloy LaF customization of frames. For unknown reason it sets the maxBounds rectangle
   * and it does it plain wrong. Setting bounds to null means default value should be taken from the underlying OS.
   */
  public synchronized void setMaximizedBounds(Rectangle bounds) {
    super.setMaximizedBounds(null);
  }

  private void setupCloseAction() {
    setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
    addWindowListener(
      new WindowAdapter() {
        public void windowClosing(@NotNull final WindowEvent e) {
          if (isTemporaryDisposed())
            return;
          final Application app = ApplicationManager.getApplication();
          app.invokeLater(new DumbAwareRunnable() {
            public void run() {
              if (app.isDisposed()) {
                ApplicationManagerEx.getApplicationEx().exit();
                return;
              }

              final Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
              if (openProjects.length > 1 || (openProjects.length == 1 && SystemInfo.isMacSystemMenu)) {
                if (myProject != null && myProject.isOpen()) {
                  ProjectUtil.closeAndDispose(myProject);
                }
                app.getMessageBus().syncPublisher(AppLifecycleListener.TOPIC).projectFrameClosed();
                WelcomeFrame.showIfNoProjectOpened();
              }
              else {
                ApplicationManagerEx.getApplicationEx().exit();
              }
            }
          }, ModalityState.NON_MODAL);
        }
      }
    );
  }

  public StatusBar getStatusBar() {
    return myRootPane == null ? null : myRootPane.getStatusBar();
  }

  public void setTitle(final String title) {
    if (myUpdatingTitle) {
      super.setTitle(title);
    } else {
      myTitle = title;
    }

    updateTitle();
  }

  public void setFrameTitle(final String text) {
    super.setTitle(text);
  }

  public void setFileTitle(final String fileTitle) {
    setFileTitle(fileTitle, null);
  }

  public void setFileTitle(@Nullable final String fileTitle, @Nullable File file) {
    myFileTitle = fileTitle;
    myCurrentFile = file;
    updateTitle();
  }

  @Override
  public IdeRootPaneNorthExtension getNorthExtension(String key) {
    return myRootPane.findByName(key);
  }

  private void updateTitle() {
    updateTitle(this, myTitle, myFileTitle, myCurrentFile);
  }

  public static void updateTitle(JFrame frame, final String title, final String fileTitle, final File currentFile) {
    if (myUpdatingTitle) return;

    try {
      myUpdatingTitle = true;

      frame.getRootPane().putClientProperty("Window.documentFile", currentFile);

      final String applicationName = ((ApplicationInfoEx)ApplicationInfo.getInstance()).getFullApplicationName();
      final Builder builder = new Builder();
      if (SystemInfo.isMac) {
        boolean addAppName = StringUtil.isEmpty(title) ||
                             ProjectManager.getInstance().getOpenProjects().length == 0 ||
                             ((ApplicationInfoEx)ApplicationInfo.getInstance()).isEAP() && !applicationName.endsWith("SNAPSHOT");
        builder.append(fileTitle).append(title).append(addAppName ? applicationName : null);
      } else {
        builder.append(title).append(fileTitle).append(applicationName);
      }

      frame.setTitle(builder.sb.toString());
    }
    finally {
      myUpdatingTitle = false;
    }
  }

  public void updateView() {
    ((IdeRootPane)getRootPane()).updateToolbar();
    ((IdeRootPane)getRootPane()).updateMainMenuActions();
    ((IdeRootPane)getRootPane()).updateNorthComponents();
  }

  private static final class Builder {
    public StringBuilder sb = new StringBuilder();

    public Builder append(@Nullable final String s) {
      if (s == null || s.length() == 0) return this;
      if (sb.length() > 0) sb.append(" - ");
      sb.append(s);
      return this;
    }
  }

  public Object getData(final String dataId) {
    if (CommonDataKeys.PROJECT.is(dataId)) {
      if (myProject != null) {
        return myProject.isInitialized() ? myProject : null;
      }
    }

    if (IdeFrame.KEY.getName().equals(dataId)) {
      return this;
    }

    return null;
  }

  public void setProject(final Project project) {
    if (WindowManager.getInstance().isFullScreenSupportedInCurrentOS() && myProject != project && project != null) {
      myRestoreFullScreen = myProject == null && shouldRestoreFullScreen(project);

      if (myProject != null) {
        storeFullScreenStateIfNeeded(false); // disable for old project
      }
    }

    myProject = project;
    if (project != null) {
      ProjectFrameBounds.getInstance(project);   // make sure the service is initialized and its state will be saved
      if (myRootPane != null) {
        myRootPane.installNorthComponents(project);
        project.getMessageBus().connect().subscribe(StatusBar.Info.TOPIC, myRootPane.getStatusBar());
      }

      installDefaultProjectStatusBarWidgets(myProject);
    }
    else {
      if (myRootPane != null) { //already disposed
        myRootPane.deinstallNorthComponents();
      }
    }

    if (project == null) {
      FocusTrackback.release(this);
    }

    if (isVisible() && myRestoreFullScreen) {
      toggleFullScreen(true);
      myRestoreFullScreen = false;
    }
  }

  @SuppressWarnings("SSBasedInspection")
  @Override
  public void setVisible(boolean b) {
    super.setVisible(b);

    if (b && myRestoreFullScreen) {
      SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
          toggleFullScreen(true);
          if (SystemInfo.isMacOSLion) {
            setBounds(ScreenUtil.getScreenRectangle(getLocationOnScreen()));
          }
          myRestoreFullScreen = false;
        }
      });
    }
  }

  private void installDefaultProjectStatusBarWidgets(@NotNull final Project project) {
    final StatusBar statusBar = getStatusBar();

    final PositionPanel positionPanel = new PositionPanel(project);
    statusBar.addWidget(positionPanel, "before " + IdeMessagePanel.FATAL_ERROR);

    final IdeNotificationArea notificationArea = new IdeNotificationArea();
    statusBar.addWidget(notificationArea, "before " + IdeMessagePanel.FATAL_ERROR);

    final EncodingPanel encodingPanel = new EncodingPanel(project);
    statusBar.addWidget(encodingPanel, "after Position");

    final LineSeparatorPanel lineSeparatorPanel = new LineSeparatorPanel(project);
    statusBar.addWidget(lineSeparatorPanel, "before " + encodingPanel.ID());

    final ToggleReadOnlyAttributePanel readOnlyAttributePanel = new ToggleReadOnlyAttributePanel(project);

    final InsertOverwritePanel insertOverwritePanel = new InsertOverwritePanel(project);
    statusBar.addWidget(insertOverwritePanel, "after Encoding");
    statusBar.addWidget(readOnlyAttributePanel, "after InsertOverwrite");

    Disposer.register(project, new Disposable() {
      public void dispose() {
        statusBar.removeWidget(encodingPanel.ID());
        statusBar.removeWidget(lineSeparatorPanel.ID());
        statusBar.removeWidget(positionPanel.ID());
        statusBar.removeWidget(notificationArea.ID());
        statusBar.removeWidget(readOnlyAttributePanel.ID());
        statusBar.removeWidget(insertOverwritePanel.ID());

        ((StatusBarEx)statusBar).removeCustomIndicationComponents();
      }
    });
  }

  public Project getProject() {
    return myProject;
  }

  public void dispose() {
    if (SystemInfo.isMac && isInFullScreen()) {
      ((MacMainFrameDecorator)myFrameDecorator).exitFullScreenAndDispose();
    }
    else {
      disposeImpl();
    }
  }

  public void disposeImpl() {
    if (isTemporaryDisposed()) {
      super.dispose();
      return;
    }
    MouseGestureManager.getInstance().remove(this);
    WelcomeFrame.notifyFrameClosed(this);

    // clear both our and swing hard refs
    if (myRootPane != null) {
      myRootPane = null;
      setRootPane(new JRootPane());
    }
    if (myFrameDecorator != null) {
      Disposer.dispose(myFrameDecorator);
      myFrameDecorator = null;
    }
    if (myWindowsBorderUpdater != null) {
      Toolkit.getDefaultToolkit().removePropertyChangeListener("win.xpstyle.themeActive", myWindowsBorderUpdater);
      myWindowsBorderUpdater = null;
    }

    FocusTrackback.release(this);

    super.dispose();
  }

  private boolean isTemporaryDisposed() {
    return myRootPane != null && myRootPane.getClientProperty(ScreenUtil.DISPOSE_TEMPORARY) != null;
  }

  public void storeFullScreenStateIfNeeded() {
    if (myFrameDecorator != null) {
      storeFullScreenStateIfNeeded(myFrameDecorator.isInFullScreen());
    }
  }

  public void storeFullScreenStateIfNeeded(boolean state) {
    if (!WindowManager.getInstance().isFullScreenSupportedInCurrentOS()) return;

    if (myProject != null) {
      PropertiesComponent.getInstance(myProject).setValue(FULL_SCREEN, String.valueOf(state));
      doLayout();
    }
  }

  public static boolean shouldRestoreFullScreen(@Nullable Project project) {
    return WindowManager.getInstance().isFullScreenSupportedInCurrentOS() &&
           project != null &&
           (SHOULD_OPEN_IN_FULL_SCREEN.get(project) == Boolean.TRUE || PropertiesComponent.getInstance(project).getBoolean(FULL_SCREEN, false));
  }

  @Override
  public void paint(@NotNull Graphics g) {
    UISettings.setupAntialiasing(g);
    //noinspection Since15
    super.paint(g);
  }

  public Rectangle suggestChildFrameBounds() {
//todo [kirillk] a dummy implementation
    final Rectangle b = getBounds();
    b.x += 100;
    b.width -= 200;
    b.y += 100;
    b.height -= 200;
    return b;
  }

  @Nullable
  public static Component findNearestModalComponent(@NotNull Component c) {
    Component eachParent = c;
    while (eachParent != null) {
      if (eachParent instanceof IdeFrame) return eachParent;
      if (eachParent instanceof JDialog) {
        if (((JDialog)eachParent).isModal()) return eachParent;
      }
      eachParent = eachParent.getParent();
    }

    return null;
  }

  public final BalloonLayout getBalloonLayout() {
    return myBalloonLayout;
  }

  @Override
  public boolean isInFullScreen() {
    return myFrameDecorator != null && myFrameDecorator.isInFullScreen();
  }

  @NotNull
  @Override
  public ActionCallback toggleFullScreen(boolean state) {
    if (myFrameDecorator != null) {
      return myFrameDecorator.toggleFullScreen(state);
    }
    IdeFrame[] frames = WindowManager.getInstance().getAllProjectFrames();
    for (IdeFrame frame : frames) {
      ((IdeFrameImpl)frame).updateBorder();
    }
    return ActionCallback.DONE;
  }

  @Override
  public void toFront() {
    super.toFront();
  }

  @Override
  public void toBack() {
    super.toBack();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy