Gridarta Editor
ScriptEditView.java
Go to the documentation of this file.
1 /*
2  * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
3  * Copyright (C) 2000-2015 The Gridarta Developers.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 package net.sf.gridarta.textedit.scripteditor;
21 
22 import java.awt.Frame;
23 import java.awt.Rectangle;
24 import java.awt.geom.RectangularShape;
25 import java.io.BufferedReader;
26 import java.io.File;
27 import java.io.FileInputStream;
28 import java.io.FileNotFoundException;
29 import java.io.IOException;
30 import java.io.InputStreamReader;
31 import java.util.ArrayList;
32 import java.util.List;
33 import java.util.prefs.Preferences;
34 import javax.swing.JDialog;
35 import javax.swing.JOptionPane;
36 import javax.swing.JTabbedPane;
37 import javax.swing.SwingConstants;
38 import javax.swing.event.ChangeEvent;
39 import javax.swing.event.ChangeListener;
40 import javax.swing.text.BadLocationException;
45 import net.sf.gridarta.utils.Exiter;
47 import net.sf.japi.swing.action.ActionBuilder;
48 import net.sf.japi.swing.action.ActionBuilderFactory;
49 import org.apache.log4j.Category;
50 import org.apache.log4j.Logger;
51 import org.jetbrains.annotations.NotNull;
52 import org.jetbrains.annotations.Nullable;
53 
59 public class ScriptEditView extends JDialog {
60 
64  @NotNull
65  private static final Category LOG = Logger.getLogger(ScriptEditView.class);
66 
70  @NotNull
71  private static final ActionBuilder ACTION_BUILDER = ActionBuilderFactory.getInstance().getActionBuilder("net.sf.gridarta");
72 
76  @NotNull
78 
82  private static final long serialVersionUID = 1L;
83 
88  @NotNull
89  private static final String WINDOW_X = "ScriptEditWindow.x";
90 
95  @NotNull
96  private static final String WINDOW_Y = "ScriptEditWindow.y";
97 
101  @NotNull
102  private static final String WINDOW_WIDTH = "ScriptEditWindow.width";
103 
107  @NotNull
108  private static final String WINDOW_HEIGHT = "ScriptEditWindow.height";
109 
113  @NotNull
114  private final Actions actions;
115 
119  @NotNull
121 
122  @NotNull
123  private final JTabbedPane tabPane; // tab pane
124 
125  @NotNull
126  private final List<JEditTextArea> textAreas; // list of 'JEditTextArea' objects, same order as tabs
127 
135  public ScriptEditView(@NotNull final ScriptEditControl control, @NotNull final Frame owner, @NotNull final Preferences preferences, @NotNull final Exiter exiter) {
136  super(owner, "Script Pad");
137  setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
138 
139  textAreas = new ArrayList<>();
140  actions = new Actions(control);
141  scriptEditUndoActions = new ScriptEditUndoActions();
142  setJMenuBar(ACTION_BUILDER.createMenuBar(true, "scriptEditMenu"));
143 
144  tabPane = new JTabbedPane(SwingConstants.TOP); // init tab pane
145  tabPane.addChangeListener(new EditTabListener(this));
146 
147  getContentPane().add(tabPane);
148  addWindowListener(new EditWindowListener(control)); // add listener for close box
149 
150  // calculate some default values in case there is no settings file
151  final RectangularShape screen = getGraphicsConfiguration().getBounds();
152  final int width = preferences.getInt(WINDOW_WIDTH, (int) (0.8 * screen.getWidth()));
153  final int height = preferences.getInt(WINDOW_HEIGHT, (int) (0.8 * screen.getHeight()));
154  final int x = preferences.getInt(WINDOW_X, (int) (screen.getX() + (screen.getWidth() - (double) width) / 2.0));
155  final int y = preferences.getInt(WINDOW_Y, (int) (screen.getY() + (screen.getHeight() - (double) height) / 2.0));
156  setBounds(x, y, width, height);
157 
158  final ExiterListener exiterListener = new ExiterListener() {
159 
160  @Override
161  public void preExitNotify() {
162  // ignore
163  }
164 
165  @Override
166  public void appExitNotify() {
167  final Rectangle bounds = getBounds();
168  preferences.putInt(WINDOW_X, bounds.x);
169  preferences.putInt(WINDOW_Y, bounds.y);
170  preferences.putInt(WINDOW_WIDTH, bounds.width);
171  preferences.putInt(WINDOW_HEIGHT, bounds.height);
172  }
173 
174  @Override
175  public void waitExitNotify() {
176  // ignore
177  }
178 
179  };
180  exiter.addExiterListener(exiterListener);
181  }
182 
183  @Deprecated
184  public void setTextAreaDefaults(@NotNull final TextAreaDefaults textAreaDefaults) {
185  this.textAreaDefaults = textAreaDefaults;
186  }
187 
193  public void addTab(@NotNull final String title, @Nullable final File file) {
194  final SyntaxDocument syntaxDocument = new SyntaxDocument();
196  final JEditTextArea ta = new JEditTextArea(textAreaDefaults, syntaxDocument, textAreaDefaults.getPaintInvalid()); // open new TextArea
197  //ta.setFont(new Font("Courier New", Font.PLAIN, 12));
198  textAreas.add(ta);
199  scriptEditUndoActions.addDocument(syntaxDocument);
200  tabPane.addTab(title, ta);
201  if (getTabCount() <= 1 || !isShowing()) {
202  setVisible(true);
203  }
204 
205  scriptEditUndoActions.setCurrentDocument(syntaxDocument);
206 
207  tabPane.setSelectedIndex(getTabCount() - 1);
208 
209  // very important: There must be a drawing update after showing the frame, to make
210  // sure the graphics context is fully initialized before calling 'setEditingFocus()'
211  //if (isFirstTimeShowing) {
212  update(getGraphics());
213  //}
214 
215  if (file != null && file.exists()) {
216  // print file into this document
217  try {
218  try (FileInputStream fis = new FileInputStream(file)) {
219  try (InputStreamReader isr = new InputStreamReader(fis)) {
220  try (BufferedReader in = new BufferedReader(isr)) {
221  boolean firstLine = true;
222  final StringBuilder buff = new StringBuilder("");
223  while (true) {
224  final String line = in.readLine();
225  if (line == null) {
226  break;
227  }
228  if (firstLine) {
229  firstLine = false;
230  } else {
231  buff.append('\n');
232  }
233  buff.append(line);
234  }
235  syntaxDocument.insertString(0, buff.toString(), null);
236  }
237  }
238  }
239  // insert buffer into the document
240  } catch (final FileNotFoundException e) {
241  if (LOG.isInfoEnabled()) {
242  LOG.info("addTab(): File '" + file.getName() + "' not found.");
243  }
244  } catch (final IOException e) {
245  if (LOG.isInfoEnabled()) {
246  LOG.info("addTab(): I/O-Error while reading '" + file.getName() + "'.");
247  }
248  } catch (final BadLocationException e) {
249  if (LOG.isInfoEnabled()) {
250  LOG.info("addTab(): Bad Location in Document!");
251  }
252  }
253  scriptEditUndoActions.resetUndo(syntaxDocument);
254  }
255 
256  ta.setEditingFocus(); // set focus to TextArea in order to respond to key press events
257  //ta.scrollToCaret(); // make sure the window shows caret (top left corner)
258 
259  ta.resetModified();
260 
261  toFront(); // bring window to front
262  }
263 
267  public void closeActiveTab() {
268  if (textAreas.isEmpty()) {
269  setVisible(false);
270  } else {
271  final int oldIndex = tabPane.getSelectedIndex();
272  final int newIndex = oldIndex >= tabPane.getTabCount() - 1 ? oldIndex - 1 : oldIndex;
273  tabPane.setSelectedIndex(newIndex);
274  scriptEditUndoActions.removeDocument(textAreas.get(oldIndex).getDocument());
275  textAreas.remove(oldIndex);
276  tabPane.remove(oldIndex);
277  actions.refresh();
278  scriptEditUndoActions.setCurrentDocument(newIndex == -1 ? null : textAreas.get(newIndex).getDocument());
279  }
280  }
281 
285  @Nullable
287  if (getTabCount() > 0) {
288  return textAreas.get(tabPane.getSelectedIndex());
289  }
290 
291  return null; // no window is open
292  }
293 
297  public int getSelectedIndex() {
298  return tabPane.getSelectedIndex();
299  }
300 
304  public int getTabCount() {
305  return tabPane.getTabCount();
306  }
307 
313  public void setTitleAt(final int index, @NotNull final String title) {
314  tabPane.setTitleAt(index, title);
315  }
316 
321  @Nullable
322  public String getActiveTitle() {
323  return getTabCount() > 0 ? tabPane.getTitleAt(tabPane.getSelectedIndex()) : null;
324  }
325 
334  public boolean askConfirm(@NotNull final String title, @NotNull final String message) {
335  return JOptionPane.showConfirmDialog(this, message, title, JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE) == JOptionPane.YES_OPTION;
336  }
337 
345  public void showMessage(@NotNull final String title, @NotNull final String message, final int messageType) {
346  JOptionPane.showMessageDialog(this, message, title, messageType);
347  }
348 
349  public void showMessage(@NotNull final String title, @NotNull final String message) {
350  JOptionPane.showMessageDialog(this, message, title, JOptionPane.INFORMATION_MESSAGE);
351  }
352 
356  private class EditTabListener implements ChangeListener {
357 
358  @NotNull
359  private final ScriptEditView view; // view
360 
361  private int index; // index of selected tab
362 
363  private EditTabListener(@NotNull final ScriptEditView view) {
364  this.view = view;
365  index = view.getSelectedIndex();
366  }
367 
368  @Override
369  public void stateChanged(@NotNull final ChangeEvent e) {
370  if (index != view.getSelectedIndex()) {
371  index = view.getSelectedIndex();
372  // active selected tab has changed
373  actions.refresh(); // refresh state of menus
374  scriptEditUndoActions.setCurrentDocument(index == -1 ? null : textAreas.get(index).getDocument());
375  }
376  }
377 
378  }
379 
380 }
void setTitleAt(final int index, @NotNull final String title)
Sets the title of the tab at specified index.
void setCurrentDocument(@Nullable final Document currentDocument)
Sets the current document.
static final String WINDOW_X
The key used to store the editor window x-coordinate in preferences file.
A document implementation that can be tokenized by the syntax highlighting system.
void setEditingFocus()
Sets the focus to this TextArea, so this component is instantly registered for key press events...
void resetUndo(@NotNull final Document document)
Forget all undo-able operations for a document.
static TokenMarker createTokenMarker(@Nullable final File file)
Creates a suitable TokenMarker for a given file.
static final ActionBuilder ACTION_BUILDER
Action Builder.
void showMessage(@NotNull final String title, @NotNull final String message, final int messageType)
Shows the given message in the UI.
final Actions actions
The actions for the script editor.
Base package of all Gridarta classes.
void removeDocument(@NotNull final Document document)
Removes a document.
static final long serialVersionUID
Serial Version UID.
boolean askConfirm(@NotNull final String title, @NotNull final String message)
Shows the given confirmation message as popup frame.
Exits the application.
Definition: Exiter.java:28
A factory for creatingTokenMarker instances for Files.
Actions used by the script editor.
Definition: Actions.java:41
Interface for listeners interested in Exiter related events.
This package contains the other part of the script editor.
String getActiveTitle()
Returns the title of the active tab.
void closeActiveTab()
Closes the active script-tab.
void addTab(@NotNull final String title, @Nullable final File file)
Adds a new TextArea Panel to the TabbedPane.
ScriptEditView(@NotNull final ScriptEditControl control, @NotNull final Frame owner, @NotNull final Preferences preferences, @NotNull final Exiter exiter)
Builds a frame but keep it hidden (it is shown when first file is opened).
ScriptEditControl - Manages events and data flow for the script editor entity.
static final String WINDOW_WIDTH
The key used to store the editor window width in preferences file.
void resetModified()
Reset the "modified" state.
void refresh()
Refreshes the enable/disable state of all menus.
Definition: Actions.java:261
void showMessage(@NotNull final String title, @NotNull final String message)
void setTextAreaDefaults(@NotNull final TextAreaDefaults textAreaDefaults)
Inner class: Listener for ChangeEvents in the tabPane.
TextAreaDefaults textAreaDefaults
The TextAreaDefaults for tabs.
void addDocument(@NotNull final Document document)
Adds a document.
final ScriptEditUndoActions scriptEditUndoActions
The undo related actions for the script editor.
static final Category LOG
The Logger for printing log messages.
static final String WINDOW_Y
The key used to store the editor window y-coordinate in preferences file.
static final String WINDOW_HEIGHT
The key used to store the editor window height in preferences file.
void setTokenMarker(@Nullable final TokenMarker tokenMarker)
Sets the token marker that is to be used to split lines of this document up into tokens.
Encapsulates default settings for a text area.