00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 package com.realtime.crossfire.jxclient.gui.label;
00023
00024 import com.realtime.crossfire.jxclient.gui.gui.AbstractGUIElement;
00025 import com.realtime.crossfire.jxclient.gui.gui.GUIElement;
00026 import com.realtime.crossfire.jxclient.gui.gui.Gui;
00027 import com.realtime.crossfire.jxclient.gui.gui.GuiAutoCloseListener;
00028 import com.realtime.crossfire.jxclient.gui.gui.RendererGuiState;
00029 import com.realtime.crossfire.jxclient.gui.gui.RendererGuiStateListener;
00030 import com.realtime.crossfire.jxclient.gui.list.GUIFloorList;
00031 import com.realtime.crossfire.jxclient.gui.list.GUIItemList;
00032 import com.realtime.crossfire.jxclient.gui.list.GUIMetaElementList;
00033 import com.realtime.crossfire.jxclient.gui.log.Buffer;
00034 import com.realtime.crossfire.jxclient.gui.log.GUILog;
00035 import com.realtime.crossfire.jxclient.gui.log.GUIMessageLog;
00036 import com.realtime.crossfire.jxclient.gui.map.GUIMap;
00037 import com.realtime.crossfire.jxclient.gui.textinput.GUIText;
00038 import com.realtime.crossfire.jxclient.server.crossfire.CrossfireServerConnection;
00039 import com.realtime.crossfire.jxclient.util.EventListenerList2;
00040 import com.realtime.crossfire.jxclient.util.Resolution;
00041 import java.awt.Color;
00042 import java.awt.Component;
00043 import java.awt.Container;
00044 import java.awt.Dimension;
00045 import java.awt.DisplayMode;
00046 import java.awt.Frame;
00047 import java.awt.Graphics;
00048 import java.awt.GraphicsConfiguration;
00049 import java.awt.GraphicsDevice;
00050 import java.awt.GraphicsEnvironment;
00051 import java.awt.Insets;
00052 import java.awt.Point;
00053 import java.awt.Rectangle;
00054 import java.awt.Toolkit;
00055 import java.awt.Window;
00056 import java.awt.event.ComponentEvent;
00057 import java.awt.event.ComponentListener;
00058 import java.awt.event.KeyEvent;
00059 import java.awt.event.MouseEvent;
00060 import java.awt.image.BufferStrategy;
00061 import java.io.IOException;
00062 import java.io.Writer;
00063 import java.text.DateFormat;
00064 import java.text.SimpleDateFormat;
00065 import java.util.Collection;
00066 import java.util.Date;
00067 import java.util.Iterator;
00068 import java.util.ListIterator;
00069 import java.util.concurrent.CopyOnWriteArrayList;
00070 import javax.swing.JFrame;
00071 import javax.swing.JLayeredPane;
00072 import javax.swing.JViewport;
00073 import javax.swing.RootPaneContainer;
00074 import javax.swing.event.MouseInputListener;
00075 import org.jetbrains.annotations.NotNull;
00076 import org.jetbrains.annotations.Nullable;
00077
00082 public class JXCWindowRenderer {
00083
00087 private static final int DEFAULT_NUM_LOOK_OBJECTS = 50;
00088
00092 private static final int DEFAULT_MAP_WIDTH = 9;
00093
00097 private static final int DEFAULT_MAP_HEIGHT = 9;
00098
00103 @Nullable
00104 private JFrame frame = null;
00105
00110 @NotNull
00111 private final Container layeredPane = new JLayeredPane() {
00112
00116 private static final long serialVersionUID = 1L;
00117
00118 @Override
00119 public void paint(final Graphics g) {
00120 super.paint(g);
00121 mouseTracker.paintActiveComponent(g);
00122 }
00123
00124 };
00125
00129 @NotNull
00130 private final MouseTracker mouseTracker;
00131
00135 @NotNull
00136 private final CrossfireServerConnection crossfireServerConnection;
00137
00141 @Nullable
00142 private final Writer debugScreen;
00143
00147 @NotNull
00148 private final GraphicsEnvironment graphicsEnvironment;
00149
00153 @NotNull
00154 private final GraphicsDevice graphicsDevice;
00155
00159 @NotNull
00160 private final DisplayMode defaultDisplayMode;
00161
00165 @NotNull
00166 private final MouseInputListener mouseInputListener = new MouseInputListener() {
00167
00168 @Override
00169 public void mouseClicked(final MouseEvent e) {
00170
00171 }
00172
00173 @Override
00174 public void mousePressed(final MouseEvent e) {
00175 mouseTracker.mousePressed(findElement(e.getComponent(), e), e);
00176 }
00177
00178 @Override
00179 public void mouseReleased(final MouseEvent e) {
00180 mouseTracker.mouseReleased(findElement(e.getComponent(), e), e);
00181 }
00182
00183 @Override
00184 public void mouseEntered(final MouseEvent e) {
00185 mouseTracker.mouseEntered(findElement(e.getComponent(), e), e);
00186 }
00187
00188 @Override
00189 public void mouseExited(final MouseEvent e) {
00190 mouseTracker.mouseExited(e);
00191 }
00192
00193 @Override
00194 public void mouseDragged(final MouseEvent e) {
00195 mouseTracker.mouseDragged(findElement(e.getComponent(), e), e);
00196 }
00197
00198 @Override
00199 public void mouseMoved(final MouseEvent e) {
00200 mouseTracker.mouseMoved(findElement(e.getComponent(), e), e);
00201 }
00202
00203 };
00204
00210 @Nullable
00211 private BufferStrategy bufferStrategy = null;
00212
00216 private int windowWidth = 0;
00217
00221 private int windowHeight = 0;
00222
00227 @NotNull
00228 private final CopyOnWriteArrayList<Gui> openDialogs = new CopyOnWriteArrayList<Gui>();
00229
00233 @NotNull
00234 private final EventListenerList2<RendererGuiStateListener> rendererGuiStateListeners = new EventListenerList2<RendererGuiStateListener>(RendererGuiStateListener.class);
00235
00239 @Nullable
00240 private Gui currentGui = null;
00241
00246 @NotNull
00247 private final Collection<GUIMap> maps = new CopyOnWriteArrayList<GUIMap>();
00248
00253 @NotNull
00254 private final Collection<GUIFloorList> floorLists = new CopyOnWriteArrayList<GUIFloorList>();
00255
00259 @Nullable
00260 private Component tooltip = null;
00261
00265 private int offsetX = 0;
00266
00270 private int offsetY = 0;
00271
00275 private boolean isFullScreen = false;
00276
00280 private boolean wasDisplayed = false;
00281
00285 @NotNull
00286 private RendererGuiState rendererGuiState = RendererGuiState.START;
00287
00291 @NotNull
00292 private final DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS ");
00293
00297 @NotNull
00298 private final ComponentListener componentListener = new ComponentListener() {
00299
00300 @Override
00301 public void componentResized(final ComponentEvent e) {
00302 final RootPaneContainer tmpFrame = frame;
00303 assert tmpFrame != null;
00304 final int width = tmpFrame.getContentPane().getWidth();
00305 final int height = tmpFrame.getContentPane().getHeight();
00306 updateWindowSize(width, height);
00307 updateServerSettings();
00308 }
00309
00310 @Override
00311 public void componentMoved(final ComponentEvent e) {
00312
00313 }
00314
00315 @Override
00316 public void componentShown(final ComponentEvent e) {
00317 updateServerSettings();
00318 }
00319
00320 @Override
00321 public void componentHidden(final ComponentEvent e) {
00322
00323 }
00324
00325 };
00326
00334 public JXCWindowRenderer(@NotNull final MouseTracker mouseTracker, @NotNull final CrossfireServerConnection crossfireServerConnection, @Nullable final Writer debugScreen) {
00335 this.mouseTracker = mouseTracker;
00336 this.crossfireServerConnection = crossfireServerConnection;
00337 this.debugScreen = debugScreen;
00338 graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
00339 graphicsDevice = graphicsEnvironment.getDefaultScreenDevice();
00340 defaultDisplayMode = graphicsDevice.getDisplayMode();
00341 }
00342
00351 public boolean setFullScreenMode(@NotNull final JFrame frame, @Nullable final Resolution resolution) {
00352 debugScreenWrite("setFullScreenMode: resolution="+(resolution == null ? "default" : resolution));
00353
00354 final DisplayMode currentDisplayMode = graphicsDevice.getDisplayMode();
00355 debugScreenWrite("setResolutionPre: current display mode="+currentDisplayMode.getWidth()+"x"+currentDisplayMode.getHeight());
00356 if (frame == this.frame && isFullScreen && bufferStrategy != null && (resolution == null || resolution.getWidth() == windowWidth && resolution.getHeight() == windowHeight)) {
00357 debugScreenWrite("setResolutionPre: no change needed");
00358 debugScreenWrite("setResolutionPre: success");
00359 return true;
00360 }
00361
00362 setResolutionPre(frame);
00363
00364 final Dimension dimension;
00365 if (resolution == null) {
00366 dimension = new Dimension(currentDisplayMode.getWidth(), currentDisplayMode.getHeight());
00367 } else {
00368 dimension = new Dimension(resolution.getWidth(), resolution.getHeight());
00369 }
00370 debugScreenWrite("setFullScreenMode: full-screen requested, dimension="+dimension);
00371 frame.setPreferredSize(dimension);
00372 frame.setResizable(false);
00373 frame.setUndecorated(true);
00374
00375
00376 if (!graphicsDevice.isFullScreenSupported()) {
00377 debugScreenWrite("setFullScreenMode: full-screen mode is not supported");
00378 graphicsDevice.setFullScreenWindow(null);
00379 isFullScreen = false;
00380 debugScreenWrite("setFullScreenMode: failure");
00381 return false;
00382 }
00383
00384 debugScreenWrite("setFullScreenMode: entering full-screen mode");
00385 graphicsDevice.setFullScreenWindow(frame);
00386 isFullScreen = true;
00387
00388 if (resolution == null || resolution.equalsDisplayMode(currentDisplayMode)) {
00389 debugScreenWrite("setFullScreenMode: requested resolution matches screen resolution");
00390 } else {
00391 if (!graphicsDevice.isDisplayChangeSupported()) {
00392 debugScreenWrite("setFullScreenMode: screen resolution change is not supported");
00393 graphicsDevice.setFullScreenWindow(null);
00394 isFullScreen = false;
00395 debugScreenWrite("setFullScreenMode: failure");
00396 return false;
00397 }
00398
00399 final DisplayMode newDisplayMode = new DisplayMode(resolution.getWidth(), resolution.getHeight(), DisplayMode.BIT_DEPTH_MULTI, DisplayMode.REFRESH_RATE_UNKNOWN);
00400 try {
00401 debugScreenWrite("setFullScreenMode: setting screen resolution to "+newDisplayMode.getWidth()+"x"+newDisplayMode.getHeight());
00402 graphicsDevice.setDisplayMode(newDisplayMode);
00403 } catch (final IllegalArgumentException ex) {
00404 debugScreenWrite("setFullScreenMode: setting screen resolution failed: "+ex.getMessage());
00405 isFullScreen = false;
00406 debugScreenWrite("setFullScreenMode: resetting screen resolution to "+defaultDisplayMode.getWidth()+"x"+defaultDisplayMode.getHeight());
00407 graphicsDevice.setDisplayMode(defaultDisplayMode);
00408 debugScreenWrite("setFullScreenMode: leaving full-screen mode");
00409 graphicsDevice.setFullScreenWindow(null);
00410 debugScreenWrite("setFullScreenMode: failure");
00411 return false;
00412 }
00413 }
00414
00415 setResolutionPost(frame, dimension);
00416 if (this.frame != null) {
00417 this.frame.removeComponentListener(componentListener);
00418 }
00419 this.frame = frame;
00420 this.frame.addComponentListener(componentListener);
00421 addMouseTracker(frame);
00422 addMouseTrackerRecursively(frame);
00423 return true;
00424 }
00425
00435 public void setWindowMode(@NotNull final JFrame frame, @Nullable final Resolution resolution, @NotNull final Resolution minResolution, final boolean fixedSize) {
00436 debugScreenWrite("setWindowMode: resolution="+(resolution == null ? "default" : resolution)+", fixedSize="+fixedSize);
00437
00438 final DisplayMode currentDisplayMode = graphicsDevice.getDisplayMode();
00439 debugScreenWrite("setResolutionPre: current display mode="+currentDisplayMode.getWidth()+"x"+currentDisplayMode.getHeight());
00440 if (frame == this.frame && !isFullScreen && bufferStrategy != null && (resolution == null || resolution.getWidth() == windowWidth && resolution.getHeight() == windowHeight)) {
00441 debugScreenWrite("setResolutionPre: no change needed");
00442 debugScreenWrite("setResolutionPre: success");
00443 return;
00444 }
00445
00446 setResolutionPre(frame);
00447
00448 debugScreenWrite("setResolutionPre: windowed mode requested");
00449 frame.setUndecorated(false);
00450 frame.setResizable(!fixedSize);
00451 final Point centerPoint = graphicsEnvironment.getCenterPoint();
00452 debugScreenWrite("setResolutionPre: screen center point is "+centerPoint);
00453 final Dimension dimension;
00454 if (resolution == null) {
00455 dimension = new Dimension(currentDisplayMode.getWidth(), currentDisplayMode.getHeight());
00456 } else {
00457 dimension = resolution.asDimension();
00458 }
00459 final int x = centerPoint.x-dimension.width/2;
00460 final int y = centerPoint.y-dimension.height/2;
00461 if (!wasDisplayed) {
00462 frame.setLocation(x, y);
00463 }
00464 frame.setVisible(true);
00465 final Insets frameInsets = frame.getInsets();
00466 debugScreenWrite("setResolutionPre: frame insets="+frameInsets);
00467
00468 final Dimension maxDimension = getMaxWindowDimension(frameInsets);
00469 debugScreenWrite("setResolutionPre: maximal window dimension="+maxDimension);
00470 if (dimension.width > maxDimension.width || dimension.height > maxDimension.height) {
00471
00472 if (resolution == null) {
00473 dimension.width = Math.max(minResolution.getWidth()+frameInsets.left+frameInsets.right, maxDimension.width);
00474 dimension.height = Math.max(minResolution.getHeight()+frameInsets.top+frameInsets.bottom, maxDimension.height);
00475 debugScreenWrite("setResolutionPre: window size exceeds maximum allowed size, reducing window size to "+dimension.width+"x"+dimension.height);
00476 } else {
00477 debugScreenWrite("setResolutionPre: window size exceeds maximum allowed size, ignoring");
00478 }
00479 }
00480
00481 if (wasDisplayed) {
00482 debugScreenWrite("setResolutionPre: resizing window to "+dimension);
00483 frame.setPreferredSize(dimension);
00484 frame.setSize(dimension);
00485 } else {
00486 wasDisplayed = true;
00487 final int x2 = centerPoint.x-dimension.width/2-frameInsets.left;
00488 final int y2 = centerPoint.y-dimension.height/2-frameInsets.top;
00489 debugScreenWrite("setResolutionPre: moving window to "+x2+"/"+y2+" "+dimension.width+"x"+dimension.height);
00490 frame.setBounds(x2, y2, dimension.width+frameInsets.left+frameInsets.right, dimension.height+frameInsets.top+frameInsets.bottom);
00491 }
00492
00493 setResolutionPost(frame, dimension);
00494 if (this.frame != null) {
00495 this.frame.removeComponentListener(componentListener);
00496 }
00497 this.frame = frame;
00498 this.frame.addComponentListener(componentListener);
00499 addMouseTracker(frame);
00500 addMouseTrackerRecursively(frame);
00501 }
00502
00508 private void setResolutionPre(@NotNull final Window frame) {
00509
00510
00511 if (isFullScreen) {
00512 debugScreenWrite("setResolutionPre: resetting screen resolution to "+defaultDisplayMode.getWidth()+"x"+defaultDisplayMode.getHeight());
00513 graphicsDevice.setDisplayMode(defaultDisplayMode);
00514 }
00515 debugScreenWrite("setResolutionPre: leaving full-screen mode");
00516 graphicsDevice.setFullScreenWindow(null);
00517 isFullScreen = false;
00518
00519 debugScreenWrite("setResolutionPre: disposing frame");
00520 frame.dispose();
00521 }
00522
00529 private void setResolutionPost(@NotNull final Window frame, @NotNull final Dimension dimension) {
00530 debugScreenWrite("setResolutionPost: creating buffer strategy");
00531 frame.createBufferStrategy(2);
00532 bufferStrategy = frame.getBufferStrategy();
00533
00534 final Insets insets = frame.getInsets();
00535 offsetX = insets.left;
00536 offsetY = insets.top;
00537 debugScreenWrite("setResolutionPost: offset="+offsetX+"x"+offsetY+" "+insets);
00538
00539 debugScreenWrite("setResolutionPost: requesting focus");
00540 frame.requestFocusInWindow();
00541
00542 updateWindowSize(dimension.width, dimension.height);
00543
00544 frame.add(layeredPane);
00545 if (currentGui != null) {
00546 addToLayeredPane(currentGui, 0, -1);
00547 if (windowWidth > 0 && windowHeight > 0) {
00548 assert currentGui != null;
00549 currentGui.setSize(windowWidth, windowHeight);
00550 }
00551
00552 frame.validate();
00553 updateServerSettings();
00554 } else {
00555 frame.validate();
00556 }
00557
00558 debugScreenWrite("setResolutionPost: success");
00559 }
00560
00566 private void updateWindowSize(final int windowWidth, final int windowHeight) {
00567 if (this.windowWidth == windowWidth && this.windowHeight == windowHeight) {
00568 return;
00569 }
00570 this.windowWidth = windowWidth;
00571 this.windowHeight = windowHeight;
00572 debugScreenWrite("updateWindowSize: gui size="+this.windowWidth+"x"+this.windowHeight);
00573 if (currentGui != null) {
00574 currentGui.setSize(windowWidth, windowHeight);
00575 }
00576 if (frame != null) {
00577 frame.validate();
00578 }
00579 }
00580
00586 @NotNull
00587 private Dimension getMaxWindowDimension(@NotNull final Insets frameInsets) {
00588 final Rectangle maximumWindowBounds = graphicsEnvironment.getMaximumWindowBounds();
00589 debugScreenWrite("getMaxWindowDimension: maximum window bounds="+maximumWindowBounds);
00590
00591 final GraphicsConfiguration graphicsConfiguration = graphicsDevice.getDefaultConfiguration();
00592 final Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(graphicsConfiguration);
00593 debugScreenWrite("getMaxWindowDimension: screen insets="+screenInsets);
00594
00595 final int maxWidth = maximumWindowBounds.width-screenInsets.left-screenInsets.right-frameInsets.left-frameInsets.right;
00596 final int maxHeight = maximumWindowBounds.height-screenInsets.top-screenInsets.bottom-frameInsets.top-frameInsets.bottom;
00597 debugScreenWrite("getMaxWindowDimension: maximum window dimension="+maxWidth+"x"+maxHeight);
00598 return new Dimension(maxWidth, maxHeight);
00599 }
00600
00604 public void endRendering() {
00605 if (isFullScreen && frame != null) {
00606 if (currentGui != null) {
00607 removeFromLayeredPane(currentGui);
00608 }
00609 final Resolution minResolution = new Resolution(1, 1);
00610 assert frame != null;
00611 setWindowMode(frame, null, minResolution, false);
00612 assert frame != null;
00613 removeMouseTracker(frame);
00614 assert frame != null;
00615 removeMouseTrackerRecursively(frame);
00616 assert frame != null;
00617 frame.removeComponentListener(componentListener);
00618 frame = null;
00619 }
00620 }
00621
00626 public void redraw(@NotNull final Graphics g) {
00627 layeredPane.paint(g);
00628 }
00629
00634 public void clearGUI(@NotNull final Gui gui) {
00635 setCurrentGui(gui);
00636 for (int ig = 0; ig < 3; ig++) {
00637 assert bufferStrategy != null;
00638 final Graphics g = bufferStrategy.getDrawGraphics();
00639 redrawBlack(g);
00640 g.dispose();
00641 assert bufferStrategy != null;
00642 bufferStrategy.show();
00643 }
00644 }
00645
00650 private void redrawBlack(@NotNull final Graphics g) {
00651 g.setColor(Color.BLACK);
00652 assert frame != null;
00653 final int width = frame.getWidth();
00654 assert frame != null;
00655 final int height = frame.getHeight();
00656 g.fillRect(0, 0, width, height);
00657 }
00658
00667 public boolean openDialog(@NotNull final Gui dialog, final boolean autoCloseOnDeactivate) {
00668 if (dialog == currentGui) {
00669 return false;
00670 }
00671
00672 if (!openDialogs.isEmpty() && openDialogs.get(openDialogs.size()-1) == dialog) {
00673 return false;
00674 }
00675
00676 if (!openDialogsRemove(dialog)) {
00677 dialog.activateDefaultElement();
00678 @Nullable final GuiAutoCloseListener guiAutoCloseListener;
00679 if (autoCloseOnDeactivate) {
00680 guiAutoCloseListener = new GuiAutoCloseListener() {
00681
00682 @Override
00683 public void autoClosed() {
00684 closeDialog(dialog);
00685 }
00686
00687 };
00688
00689 } else {
00690 guiAutoCloseListener = null;
00691 }
00692 dialog.setGuiAutoCloseListener(guiAutoCloseListener);
00693 }
00694 openDialogsAdd(dialog);
00695 updateServerSettings();
00696 return true;
00697 }
00698
00703 public void raiseDialog(@NotNull final Gui dialog) {
00704 if (dialog == currentGui) {
00705 return;
00706 }
00707
00708 if (!openDialogs.isEmpty() && openDialogs.get(openDialogs.size()-1) == dialog) {
00709 return;
00710 }
00711
00712 if (!isDialogOpen(dialog)) {
00713 return;
00714 }
00715
00716 if (!openDialogsRemove(dialog)) {
00717 assert false;
00718 }
00719 openDialogsAdd(dialog);
00720 updateServerSettings();
00721 }
00722
00728 public boolean isDialogOpen(@NotNull final Gui dialog) {
00729 return openDialogs.contains(dialog);
00730 }
00731
00737 @NotNull
00738 public Iterable<Gui> getOpenDialogs() {
00739 return new Iterable<Gui>() {
00740
00741 @Override
00742 public Iterator<Gui> iterator() {
00743 return new OpenDialogsIterator();
00744 }
00745
00746 };
00747 }
00748
00753 @SuppressWarnings("NullableProblems")
00754 public void setCurrentGui(@NotNull final Gui gui) {
00755 if (frame != null && currentGui != null) {
00756 removeFromLayeredPane(currentGui);
00757 }
00758 currentGui = gui;
00759
00760 if (frame != null) {
00761 addToLayeredPane(currentGui, 0, -1);
00762 }
00763
00764 if (windowWidth > 0 && windowHeight > 0) {
00765 assert currentGui != null;
00766 currentGui.setSize(windowWidth, windowHeight);
00767 }
00768 if (frame != null) {
00769 frame.validate();
00770 }
00771 updateServerSettings();
00772 }
00773
00780 public boolean closeDialog(@NotNull final Gui dialog) {
00781 if (!openDialogsRemove(dialog)) {
00782 return false;
00783 }
00784
00785 dialog.setActiveElementActive(false);
00786 updateServerSettings();
00787 return true;
00788 }
00789
00795 public boolean toggleDialog(@NotNull final Gui dialog) {
00796 if (dialog == currentGui) {
00797 return true;
00798 }
00799
00800 if (openDialogsRemove(dialog)) {
00801 dialog.setActiveElementActive(false);
00802 updateServerSettings();
00803 return false;
00804 }
00805
00806 dialog.setGuiAutoCloseListener(null);
00807 openDialogsAdd(dialog);
00808 dialog.activateDefaultElement();
00809 updateServerSettings();
00810 return true;
00811 }
00812
00818 public void setTooltip(@Nullable final Component tooltip) {
00819 if (this.tooltip != null) {
00820 layeredPane.remove(this.tooltip);
00821 }
00822 this.tooltip = tooltip;
00823 if (this.tooltip != null) {
00824 layeredPane.add(this.tooltip, 2, -1);
00825 }
00826 }
00827
00832 public void setGuiState(@NotNull final RendererGuiState rendererGuiState) {
00833 if (this.rendererGuiState == rendererGuiState) {
00834 return;
00835 }
00836
00837 this.rendererGuiState = rendererGuiState;
00838 for (final Gui dialog : openDialogs) {
00839 removeFromLayeredPane(dialog);
00840 if (!dialog.isHidden(rendererGuiState)) {
00841 addToLayeredPane(dialog, 1, 0);
00842 }
00843 }
00844 if (frame != null) {
00845 frame.validate();
00846 }
00847 updateServerSettings();
00848 for (final RendererGuiStateListener listener : rendererGuiStateListeners.getListeners()) {
00849 listener.guiStateChanged(rendererGuiState);
00850 }
00851 }
00852
00857 @NotNull
00858 public RendererGuiState getGuiState() {
00859 return rendererGuiState;
00860 }
00861
00867 public void addGuiStateListener(@NotNull final RendererGuiStateListener listener) {
00868 rendererGuiStateListeners.add(listener);
00869 }
00870
00876 private void openDialogsAdd(@NotNull final Gui dialog) {
00877 if (openDialogs.contains(dialog)) {
00878 raiseDialog(dialog);
00879 return;
00880 }
00881
00882 dialog.autoSize(windowWidth, windowHeight);
00883
00884 final Point mouse = frame == null ? null : frame.getMousePosition(true);
00885 if (mouse == null || dialog.isHidden(rendererGuiState)) {
00886 openDialogs.add(dialog);
00887 if (!dialog.isHidden(rendererGuiState)) {
00888 openDialogInt(dialog);
00889 }
00890 } else {
00891 if (dialog.isWithinDrawingArea(mouse.x, mouse.y)) {
00892 final MouseEvent mouseEvent = new MouseEvent(frame, 0, System.currentTimeMillis(), 0, mouse.x, mouse.y, 0, false);
00893 mouseTracker.mouseExited(mouseEvent);
00894 openDialogs.add(dialog);
00895 assert !dialog.isHidden(rendererGuiState);
00896 openDialogInt(dialog);
00897 mouseTracker.mouseEntered(findElement(mouseEvent), mouseEvent);
00898 } else {
00899 openDialogs.add(dialog);
00900 assert !dialog.isHidden(rendererGuiState);
00901 openDialogInt(dialog);
00902 }
00903 }
00904 }
00905
00910 private void openDialogInt(@NotNull final Gui dialog) {
00911 addToLayeredPane(dialog, 1, 0);
00912 final Dimension preferredSize = dialog.getPreferredSize();
00913 final Dimension size;
00914 if (preferredSize == null) {
00915 size = new Dimension(320, 200);
00916 } else {
00917 size = new Dimension(Math.min(preferredSize.width, windowWidth), Math.min(preferredSize.height, windowHeight));
00918 }
00919 dialog.setSize(size);
00920 if (frame != null) {
00921 frame.validate();
00922 }
00923 }
00924
00931 private boolean openDialogsRemove(@NotNull final Gui dialog) {
00932 if (!openDialogs.contains(dialog)) {
00933 return false;
00934 }
00935
00936 final Point mouse = frame == null ? null : frame.getMousePosition(true);
00937 if (mouse == null) {
00938 openDialogs.remove(dialog);
00939 removeFromLayeredPane(dialog);
00940 if (frame != null) {
00941 frame.validate();
00942
00943 assert frame != null;
00944 frame.repaint();
00945 }
00946 } else {
00947 if (dialog.isWithinDrawingArea(mouse.x, mouse.y)) {
00948 final MouseEvent mouseEvent = new MouseEvent(frame, 0, System.currentTimeMillis(), 0, mouse.x, mouse.y, 0, false);
00949 mouseTracker.mouseExited(mouseEvent);
00950 openDialogs.remove(dialog);
00951 removeFromLayeredPane(dialog);
00952 if (frame != null) {
00953 frame.validate();
00954
00955 assert frame != null;
00956 frame.repaint();
00957 }
00958 mouseTracker.mouseEntered(findElement(mouseEvent), mouseEvent);
00959 } else {
00960 openDialogs.remove(dialog);
00961 removeFromLayeredPane(dialog);
00962 if (frame != null) {
00963 frame.validate();
00964
00965 assert frame != null;
00966 frame.repaint();
00967 }
00968 }
00969 }
00970
00971 return true;
00972 }
00973
00979 public boolean deactivateCommandInput() {
00980 for (final Gui dialog : openDialogs) {
00981 if (!dialog.isHidden(rendererGuiState)) {
00982 if (dialog.deactivateCommandInput()) {
00983 return true;
00984 }
00985 if (dialog.isModal()) {
00986 return false;
00987 }
00988 }
00989 }
00990
00991 assert currentGui != null;
00992 return currentGui.deactivateCommandInput();
00993 }
00994
00999 @Nullable
01000 public Buffer getActiveMessageBuffer() {
01001 for (final Gui dialog : openDialogs) {
01002 if (!dialog.isHidden(rendererGuiState)) {
01003 final Buffer buffer = getActiveMessageBuffer(dialog);
01004 if (buffer != null) {
01005 return buffer;
01006 }
01007 if (dialog.isModal()) {
01008 return null;
01009 }
01010 }
01011 }
01012
01013 assert currentGui != null;
01014 return getActiveMessageBuffer(currentGui);
01015 }
01016
01022 @Nullable
01023 private static Buffer getActiveMessageBuffer(@NotNull final Gui gui) {
01024 final GUILog buffer = gui.getFirstElement(GUIMessageLog.class);
01025 return buffer == null ? null : buffer.getBuffer();
01026 }
01027
01032 public void setSelectedHostname(@NotNull final String serverName) {
01033 assert currentGui != null;
01034 final GUIMetaElementList metaElementList = currentGui.getFirstElement(GUIMetaElementList.class);
01035 if (metaElementList != null) {
01036 metaElementList.setSelectedHostname(serverName);
01037 }
01038 }
01039
01046 @Nullable
01047 public GUIText activateCommandInput() {
01048
01049 assert currentGui != null;
01050 final GUIText textArea1 = activateCommandInput(currentGui);
01051 if (textArea1 != null) {
01052 return textArea1;
01053 }
01054
01055
01056 for (final Gui dialog : openDialogs) {
01057 if (!dialog.isHidden(rendererGuiState)) {
01058 final GUIText textArea2 = activateCommandInput(dialog);
01059 if (textArea2 != null) {
01060 openDialog(dialog, false);
01061 return textArea2;
01062 }
01063 }
01064 if (dialog.isModal()) {
01065 return null;
01066 }
01067 }
01068
01069 return null;
01070 }
01071
01077 public boolean handleKeyPress(@NotNull final KeyEvent e) {
01078 assert currentGui != null;
01079 return currentGui.handleKeyPress(e);
01080 }
01081
01085 private class OpenDialogsIterator implements Iterator<Gui> {
01086
01091 @NotNull
01092 private final ListIterator<Gui> it = openDialogs.listIterator(openDialogs.size());
01093
01094 @Override
01095 public boolean hasNext() {
01096 return it.hasPrevious();
01097 }
01098
01099 @SuppressWarnings("IteratorNextCanNotThrowNoSuchElementException")
01100 @NotNull
01101 @Override
01102 public Gui next() {
01103 return it.previous();
01104 }
01105
01106 @Override
01107 public void remove() {
01108 throw new UnsupportedOperationException();
01109 }
01110
01111 }
01112
01117 public int getWindowWidth() {
01118 return windowWidth;
01119 }
01120
01125 public int getWindowHeight() {
01126 return windowHeight;
01127 }
01128
01135 @Nullable
01136 private static AbstractGUIElement findElement(@NotNull final Component component, @NotNull final MouseEvent mouseEvent) {
01137 for (Component result = component; result != null; result = result.getParent()) {
01138 if (result instanceof AbstractGUIElement) {
01139 return (AbstractGUIElement)result;
01140 }
01141 if (result instanceof JViewport) {
01142 final JViewport viewport = (JViewport)result;
01143 final Point position = viewport.getViewPosition();
01144 mouseEvent.translatePoint(-position.x, -position.y);
01145 }
01146 }
01147 return null;
01148 }
01149
01157 @Nullable
01158 private AbstractGUIElement findElement(@NotNull final MouseEvent e) {
01159 final MouseEvent ce = e;
01160 AbstractGUIElement elected = null;
01161
01162 final int eX = ce.getX();
01163 final int eY = ce.getY();
01164 for (final Gui dialog : openDialogs) {
01165 if (!dialog.isHidden(rendererGuiState)) {
01166 elected = getElementFromPoint(dialog, eX-dialog.getX(), eY-dialog.getY());
01167 if (elected != null) {
01168 break;
01169 }
01170 }
01171 if (dialog.isModal()) {
01172 return null;
01173 }
01174 }
01175
01176 if (elected == null) {
01177 assert currentGui != null;
01178 elected = getElementFromPoint(currentGui, eX, eY);
01179 }
01180
01181 return elected;
01182 }
01183
01193 @Nullable
01194 private AbstractGUIElement getElementFromPoint(@NotNull final Gui gui, final int eX, final int eY) {
01195 final int x = eX-offsetX;
01196 final int y = eY-offsetY;
01197 return gui.getElementFromPoint(x, y);
01198 }
01199
01204 private void debugScreenWrite(@NotNull final CharSequence message) {
01205 if (debugScreen == null) {
01206 return;
01207 }
01208
01209 try {
01210 debugScreen.append(simpleDateFormat.format(new Date()));
01211 debugScreen.append(message);
01212 debugScreen.append("\n");
01213 debugScreen.flush();
01214 } catch (final IOException ex) {
01215 System.err.println("Cannot write screen debug: "+ex.getMessage());
01216 System.exit(1);
01217 throw new AssertionError();
01218 }
01219 }
01220
01227 private void addToLayeredPane(@NotNull final Component component, final int layer, final int index) {
01228 layeredPane.add(component, layer, index);
01229 addMouseTrackerRecursively(component);
01230 addComponent(component);
01231 }
01232
01237 private void removeFromLayeredPane(@NotNull final Component component) {
01238 layeredPane.remove(component);
01239 removeMouseTrackerRecursively(component);
01240 removeComponent(component);
01241 }
01242
01247 private void addMouseTracker(@NotNull final Component component) {
01248 component.addMouseListener(mouseInputListener);
01249 component.addMouseMotionListener(mouseInputListener);
01250 }
01251
01256 private void removeMouseTracker(@NotNull final Component component) {
01257 component.removeMouseListener(mouseInputListener);
01258 component.removeMouseMotionListener(mouseInputListener);
01259 }
01260
01266 private void addMouseTrackerRecursively(@NotNull final Component component) {
01267 addMouseTracker(component);
01268 if (component instanceof Container) {
01269 final Container container = (Container)component;
01270 for (int i = 0; i < container.getComponentCount(); i++) {
01271 addMouseTrackerRecursively(container.getComponent(i));
01272 }
01273 }
01274 }
01275
01281 private void removeMouseTrackerRecursively(@NotNull final Component component) {
01282 removeMouseTracker(component);
01283 if (component instanceof Container) {
01284 final Container container = (Container)component;
01285 for (int i = 0; i < container.getComponentCount(); i++) {
01286 removeMouseTrackerRecursively(container.getComponent(i));
01287 }
01288 }
01289 }
01290
01295 private void addComponent(@NotNull final Component component) {
01296 if (component instanceof GUIMap) {
01297 final GUIMap map = (GUIMap)component;
01298 maps.add(map);
01299 }
01300 if (component instanceof GUIFloorList) {
01301 final GUIFloorList floorList = (GUIFloorList)component;
01302 floorLists.add(floorList);
01303 }
01304 if (component instanceof Container) {
01305 final Container container = (Container)component;
01306 for (int i = 0; i < container.getComponentCount(); i++) {
01307 addComponent(container.getComponent(i));
01308 }
01309 }
01310 }
01311
01316 private void removeComponent(@NotNull final Component component) {
01317 if (component instanceof GUIMap) {
01318 final GUIMap map = (GUIMap)component;
01319 maps.remove(map);
01320 }
01321 if (component instanceof GUIFloorList) {
01322 final GUIFloorList floorList = (GUIFloorList)component;
01323 floorLists.remove(floorList);
01324 }
01325 if (component instanceof Container) {
01326 final Container container = (Container)component;
01327 for (int i = 0; i < container.getComponentCount(); i++) {
01328 removeComponent(container.getComponent(i));
01329 }
01330 }
01331 }
01332
01337 public void updateServerSettings() {
01338 if (frame == null || !frame.isVisible()) {
01339 return;
01340 }
01341
01342 final Dimension mapSize = getMapSize();
01343 crossfireServerConnection.setPreferredMapSize(mapSize.width, mapSize.height);
01344 crossfireServerConnection.setPreferredNumLookObjects(getNumLookObjects());
01345 }
01346
01351 @NotNull
01352 private Dimension getMapSize() {
01353 int width = DEFAULT_MAP_WIDTH;
01354 int height = DEFAULT_MAP_HEIGHT;
01355 for (final GUIMap map : maps) {
01356 width = Math.max(width, map.getPreferredMapWidth());
01357 height = Math.max(height, map.getPreferredMapHeight());
01358 }
01359 return new Dimension(width, height);
01360 }
01361
01366 private int getNumLookObjects() {
01367 int minNumLookObjects = Integer.MAX_VALUE;
01368 for (final GUIFloorList floorList : floorLists) {
01369 minNumLookObjects = Math.min(minNumLookObjects, floorList.getNumLookObjects());
01370 }
01371 if (minNumLookObjects < Integer.MAX_VALUE) {
01372 return minNumLookObjects;
01373 }
01374
01375 return DEFAULT_NUM_LOOK_OBJECTS;
01376 }
01377
01384 @Nullable
01385 public static GUIText activateCommandInput(@NotNull final Gui gui) {
01386 final GUIText textArea = gui.getFirstElement(GUIText.class);
01387 if (textArea == null) {
01388 return null;
01389 }
01390
01391 if (!textArea.getName().equals("command")) {
01392 return null;
01393 }
01394
01395 textArea.setActive(true);
01396 return textArea;
01397 }
01398
01399 }