com.codename1.impl.javase.simulator.AppFrame Maven / Gradle / Ivy
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.codename1.impl.javase.simulator;
import com.codename1.impl.javase.JavaSEPort;
import com.codename1.impl.javase.util.SwingUtils;
import java.awt.*;
import java.awt.List;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.*;
import java.util.Timer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import javax.swing.*;
import javax.swing.border.Border;
/**
*
* @author shannah
*/
public class AppFrame extends JPanel {
private static final long PREFS_UPDATE_DELAY = 2000L;
private static final long PREFS_UPDATE_PERIOD = 2000L;
private boolean initialized;
private JTabbedPane topPanel, leftPanel, centerPanel, rightPanel, bottomPanel;
private JSplitPane outerSplit, innerSplit, centerSplit;
private Map appPanels = new HashMap();
private Map windows = new HashMap();
private java.util.List updateCallbacks = new ArrayList();
private boolean shouldSavePreferences = false;
private JScrollPane canvasScroller;
private JComponent canvas;
private class AppPanelWindowHandle {
private AppPanel panel;
private JFrame window;
private AppFrame.FrameLocation previousLocation;
private AppPanelWindowHandle(AppPanel panel, AppFrame.FrameLocation previousLocation) {
this.panel = panel;
this.previousLocation = previousLocation;
}
private void fitWindowOntoScreen() {
if (window == null) throw new IllegalStateException("Cannot fit window onto screen until it is created");
Point pos = new Point(window.getBounds().getLocation());
pos.x += window.getWidth()/2;
pos.y += window.getHeight()/2;
Rectangle screenBounds = SwingUtils.getScreenBoundsAt(pos);
if (screenBounds == null) {
window.pack();
window.setLocationByPlatform(true);
} else if (!screenBounds.contains(window.getBounds())) {
Rectangle newBounds = new Rectangle();
newBounds.width = window.getWidth();
newBounds.height = window.getHeight();
newBounds.x = window.getX();
if (newBounds.x < screenBounds.x) {
newBounds.x = screenBounds.x;
} else if (newBounds.x > screenBounds.width + screenBounds.x) {
newBounds.x = screenBounds.x;
}
if (newBounds.y < screenBounds.y) {
newBounds.y = screenBounds.y;
} else if (newBounds.y > screenBounds.y + screenBounds.height) {
newBounds.y = screenBounds.y;
}
if (newBounds.x + 100 > screenBounds.x+screenBounds.width) {
newBounds.x = screenBounds.x + screenBounds.width - 100;
}
if (newBounds.y + 100 > screenBounds.y + screenBounds.height) {
newBounds.y = screenBounds.y + screenBounds.height - 100;
}
window.setBounds(newBounds);
}
}
private void show() {
if (window == null) {
window = new JFrame(panel.getLabel());
window.setAlwaysOnTop(panel.isPreferredAlwaysOnTop());
window.getContentPane().setLayout(new BorderLayout());
//window.setPreferredSize(new Dimension(panel.getPreferredSize()));
Container parent = panel.getParent();
if (parent != null) {
parent.remove(panel);
}
window.getContentPane().add(panel, BorderLayout.CENTER);
window.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
JComponent contentPane = (JComponent) window.getContentPane();
panel.setSize(new Dimension(contentPane.getSize()));
int paddingV = 0;
int paddingH = 0;
Border border = contentPane.getBorder();
if (border != null) {
Insets insets = border.getBorderInsets(contentPane);
paddingV += insets.top + insets.bottom;
paddingH += insets.left + insets.right;
}
BorderLayout contentPaneLayout = (BorderLayout)contentPane.getLayout();
Component east = contentPaneLayout.getLayoutComponent(BorderLayout.EAST);
Component west = contentPaneLayout.getLayoutComponent(BorderLayout.WEST);
Component north = contentPaneLayout.getLayoutComponent(BorderLayout.NORTH);
Component south = contentPaneLayout.getLayoutComponent(BorderLayout.SOUTH);
if (east != null) {
paddingH += east.getWidth() + contentPaneLayout.getHgap();
}
if (west != null) {
paddingH += west.getWidth() + contentPaneLayout.getHgap();
}
if (north != null) {
paddingV += north.getHeight() + contentPaneLayout.getVgap();
}
if (south != null) {
paddingV += south.getHeight() + contentPaneLayout.getVgap();
}
panel.setSize(panel.getSize().width-paddingH, panel.getSize().height - paddingV);
panel.revalidate();
}
});
//window.setSize(new Dimension(window.getPreferredSize()));
//window.setLocationByPlatform(true);
window.setBounds(panel.getPreferredWindowBounds());
window.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
window.addWindowListener(frameListener);
window.addComponentListener(frameListener);
window.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
FrameLocation target = previousLocation;
if (target == null) {
target = panel.getPreferredInternalFrame();
}
if (target != null) {
if (windows.containsKey(panel)) {
moveTo(panel, target);
}
} else {
if (windows.containsKey(panel)) {
removePanel(panel);
}
}
}
});
decoratePanelWindow(panel, window);
fitWindowOntoScreen();
}
window.setVisible(true);
}
private void dispose() {
if (window != null) {
window.dispose();
window = null;
}
}
}
protected void decoratePanelWindow(AppPanel panel, Window window) {
}
public AppFrame(String name) {
setLayout(new BorderLayout());
setName(name);
initAppFrameUI();
}
protected void initAppFrameUI() {
Dimension preferredSize = new Dimension(SwingUtils.getScreenSize());
setMinimumSize(new Dimension(300, 300));
setPreferredSize(SwingUtils.getScreenSize());
topPanel = new JTabbedPane();
topPanel.setName("topPanel");
leftPanel = new JTabbedPane();
leftPanel.setName("leftPanel");
centerPanel = new JTabbedPane();
centerPanel.setName("centerPanel");
rightPanel = new JTabbedPane();
rightPanel.setName("rightPanel");
bottomPanel = new JTabbedPane();
bottomPanel.setName("bottomPanel");
initPanels(topPanel, leftPanel, centerPanel, rightPanel, bottomPanel);
innerSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
JavaSEPort.instance.registerSplitPaneWithBlit(innerSplit);
innerSplit.setName("innerSplit");
setDividerLocationIfChanged(innerSplit, 600);
outerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
JavaSEPort.instance.registerSplitPaneWithBlit(outerSplit);
outerSplit.setName("outerSplit");
setDividerLocationIfChanged(outerSplit, 0);
centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
JavaSEPort.instance.registerSplitPaneWithBlit(centerSplit);
centerSplit.setName("centerSplit");
setDividerLocationIfChanged(centerSplit, 600);
outerSplit.setLeftComponent(leftPanel);
outerSplit.setRightComponent(innerSplit);
innerSplit.setTopComponent(centerSplit);
innerSplit.setBottomComponent(bottomPanel);
centerSplit.setLeftComponent(centerPanel);
centerSplit.setRightComponent(rightPanel);
applyPreferences();
addComponentListener(frameListener);
outerSplit.addPropertyChangeListener(frameListener);
innerSplit.addPropertyChangeListener(frameListener);
centerSplit.addPropertyChangeListener(frameListener);
add(outerSplit, BorderLayout.CENTER);
updateAppFrameUI();
initialized = true;
}
String getPreferencesPrefix() {
String prefix = getName();
if (prefix == null) return "AppFrame.";
return prefix + ".AppFrame.";
}
private static Preferences prefs;
private static Preferences prefs() {
if (prefs == null) {
prefs = Preferences.userNodeForPackage(AppFrame.class);
}
return prefs;
}
private void applyPreferences() {
String prefix = getPreferencesPrefix();
Preferences prefs = prefs();
centerSplit.setDividerLocation(Math.max(0, prefs.getInt(prefix+"centerSplit.dividerLocation", centerSplit.getDividerLocation())));
outerSplit.setDividerLocation(Math.max(0, prefs.getInt(prefix+"outerSplit.dividerLocation", outerSplit.getDividerLocation())));
innerSplit.setDividerLocation(Math.max(0, prefs.getInt(prefix+"innerSplit.dividerLocation", innerSplit.getDividerLocation())));
Dimension preferredSize = new Dimension(getPreferredSize());
preferredSize.width = prefs.getInt(prefix+"width", preferredSize.width);
preferredSize.height = prefs.getInt(prefix+"height", preferredSize.height);
setPreferredSize(preferredSize);
}
private void savePreferences() {
shouldSavePreferences = false;
Preferences prefs = prefs();
String prefix = getPreferencesPrefix();
prefs.putInt(prefix+"innerSplit.dividerLocation", innerSplit.getDividerLocation());
prefs.putInt(prefix+"outerSplit.dividerLocation", outerSplit.getDividerLocation());
prefs.putInt(prefix+"centerSplit.dividerLocation", centerSplit.getDividerLocation());
if (getWidth() > getMinimumSize().width) {
prefs.putInt(prefix+"width", getWidth());
}
if (getHeight() > getMinimumSize().height) {
prefs.putInt(prefix + "height", getHeight());
}
for (AppPanel panel : appPanels.values()) {
panel.savePreferences(this, prefs);
}
try {
prefs.flush();
} catch (BackingStoreException ex) {
Logger.getLogger(AppFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
void initPanel(JComponent panel) {
if (panel instanceof JTabbedPane) {
JTabbedPane jTabbedPane = (JTabbedPane) panel;
} else {
panel.setLayout(new BorderLayout());
}
}
private void initPanels(JComponent... panels) {
for (JComponent panel : panels) {
initPanel(panel);
}
}
private boolean inAppFrameUI = false;
public void updateAppFrameUI() {
if (inAppFrameUI) {
return;
}
inAppFrameUI = true;
try {
} finally {
inAppFrameUI = false;
}
if (!updateCallbacks.isEmpty()) {
for (UpdatableUI callback : updateCallbacks) {
callback.onUpdateAppFrameUI(this);
}
}
}
private boolean isDividerChange(AppEvent event) {
return (event.getSourceEvent() instanceof PropertyChangeEvent &&
((PropertyChangeEvent) event.getSourceEvent()).getPropertyName().equals(JSplitPane.DIVIDER_LOCATION_PROPERTY)
);
}
private boolean isResizeEvent(AppEvent event) {
return (event.getSourceEvent() instanceof ComponentEvent &&
((ComponentEvent)event.getSourceEvent()).getID() == ComponentEvent.COMPONENT_RESIZED);
}
protected void respondAppFrameUI(AppEvent event) {
if (isDividerChange(event)) {
shouldSavePreferences = true;
} else if (isResizeEvent(event)) {
shouldSavePreferences = true;
}
updateAppFrameUI();
}
public static enum FrameLocation {
LeftPanel,
RightPanel,
CenterPanel,
BottomPanel,
SeparateWindow
}
public static enum PanelName {
Canvas,
ComponentInspector,
ComponentDetailsEditor,
}
public void add(AppPanel comp) {
comp.applyPreferences(this, prefs());
add(comp, comp.getPreferredFrame());
}
private JTabbedPane getPanel(FrameLocation location) {
switch (location) {
case LeftPanel:
return leftPanel;
case RightPanel:
return rightPanel;
case BottomPanel:
return bottomPanel;
case CenterPanel:
return centerPanel;
case SeparateWindow:
return null;
}
throw new IllegalArgumentException("Unsupported location in getPanel() "+location);
}
public void add(AppPanel comp, FrameLocation location) {
if (windows.containsKey(comp)) {
throw new IllegalStateException("Panel is already added to the app frame in its own window.");
}
if (getPanelLocation(comp) != null) {
throw new IllegalStateException("Panel is already added to this app frame.");
}
Container parent = comp.getParent();
if (parent != null) {
parent.remove(comp);
}
appPanels.put(comp.getId(), comp);
comp.setAppFrame(this);
if (location != FrameLocation.SeparateWindow) {
JTabbedPane pane = getPanel(location);
pane.addTab(comp.getLabel(), comp);
} else {
AppPanelWindowHandle windowHandle = new AppPanelWindowHandle(comp, null);
windows.put(comp, windowHandle);
windowHandle.show();
}
comp.savePreferences(this, prefs());
setShouldSavePreferences();
}
public AppPanel getAppPanelById(String id) {
return appPanels.get(id);
}
private JTabbedPane getParentTabbedPane(java.awt.Component cmp) {
java.awt.Component parent = cmp.getParent();
if (parent == null) return null;
if (parent instanceof JTabbedPane) {
return (JTabbedPane)parent;
} else {
return getParentTabbedPane(parent);
}
}
public AppFrame.FrameLocation getPanelLocation(AppPanel panel) {
if (windows.containsKey(panel)) {
return FrameLocation.SeparateWindow;
}
java.awt.Container parent = getParentTabbedPane(panel);
if (parent == bottomPanel) {
return FrameLocation.BottomPanel;
} else if (parent == leftPanel) {
return FrameLocation.LeftPanel;
} else if (parent == rightPanel) {
return FrameLocation.RightPanel;
} else if (parent == centerPanel) {
return FrameLocation.CenterPanel;
}
return null;
}
public void removePanel(AppPanel panel) {
FrameLocation oldLocation = getPanelLocation(panel);
if (oldLocation == FrameLocation.SeparateWindow) {
AppPanelWindowHandle handle = windows.get(panel);
if (handle == null) {
throw new IllegalStateException("Attempt to remove window, but it isn't registered.");
}
windows.remove(panel);
handle.dispose();
} else {
JTabbedPane tabbedPane = getParentTabbedPane(panel);
tabbedPane.remove(panel);
}
appPanels.remove(panel.getId());
}
public void moveTo(AppPanel panel, FrameLocation location) {
FrameLocation oldLocation = getPanelLocation(panel);
if (oldLocation == location) return;
if (oldLocation == FrameLocation.SeparateWindow) {
AppPanelWindowHandle handle = windows.get(panel);
if (handle == null) {
throw new IllegalStateException("Panel window not registered");
}
windows.remove(panel);
Container parent = panel.getParent();
if (parent != null) {
parent.remove(panel);
}
handle.dispose();
} else {
JTabbedPane tabbedPane = getPanel(oldLocation);
tabbedPane.remove(panel);
}
add(panel, location);
if (location == FrameLocation.SeparateWindow) {
AppPanelWindowHandle handle = windows.get(panel);
if (handle == null) {
throw new IllegalStateException("Cannot find window handle after adding to separate window");
}
handle.previousLocation = oldLocation;
}
}
private Timer timer;
private TimerTask timerTask;
private class FrameListener implements PropertyChangeListener, ComponentListener, WindowListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (!initialized) return;
if (JSplitPane.DIVIDER_LOCATION_PROPERTY.equals(evt.getPropertyName())) {
respondAppFrameUI(new AppEvent(evt));
}
}
@Override
public void componentResized(ComponentEvent e) {
if (!initialized) return;
respondAppFrameUI(new AppEvent(e));
}
@Override
public void componentMoved(ComponentEvent e) {
}
@Override
public void componentShown(ComponentEvent e) {
}
@Override
public void componentHidden(ComponentEvent e) {
}
@Override
public void windowOpened(WindowEvent e) {
setShouldSavePreferences();
}
@Override
public void windowClosing(WindowEvent e) {
}
@Override
public void windowClosed(WindowEvent e) {
setShouldSavePreferences();
}
@Override
public void windowIconified(WindowEvent e) {
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowActivated(WindowEvent e) {
}
@Override
public void windowDeactivated(WindowEvent e) {
}
}
private FrameListener frameListener = new FrameListener();
@Override
public void addNotify() {
timer = new Timer();
timerTask = new TimerTask() {
@Override
public void run() {
if (shouldSavePreferences) {
savePreferences();
}
}
};
timer.schedule(timerTask, PREFS_UPDATE_DELAY, PREFS_UPDATE_PERIOD);
super.addNotify();
}
@Override
public void removeNotify() {
if (timer != null) {
timer.cancel();
timerTask.cancel();
timer = null;
timerTask = null;
}
super.removeNotify();
}
void setShouldSavePreferences() {
shouldSavePreferences = true;
}
private void setDividerLocationIfChanged(JSplitPane pane, int location) {
if (pane.getDividerLocation() != location) {
pane.setDividerLocation(location);
}
}
JFrame getWindow(AppPanel panel) {
AppPanelWindowHandle handle = windows.get(panel);
if (handle == null) {
return null;
}
return handle.window;
}
public void registerUpdateCallback(UpdatableUI callback) {
updateCallbacks.add(callback);
}
public void deregisterUpdateCallback(UpdatableUI callback) {
updateCallbacks.remove(callback);
}
public static interface UpdatableUI {
public void onUpdateAppFrameUI(AppFrame frame);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy