001: // Copyright (c) 2002 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.jemacs.buffer;
005:
006: import gnu.lists.*;
007: import gnu.mapping.*;
008:
009: public abstract class EWindow {
010: public EFrame frame;
011: public Buffer buffer;
012:
013: protected int[] pendingKeys = null;
014: protected int pendingLength = 0;
015:
016: /** Previous window in cyclic window ordering. */
017: protected EWindow prevWindow;
018:
019: /** Next window in cyclic window ordering. */
020: protected EWindow nextWindow;
021:
022: /** Nominal height in pixels of a character, if non-zero. */
023: protected int charHeight;
024:
025: /** Nominal width in pixels of a character, if non-zero. */
026: protected int charWidth;
027:
028: public EWindow(Buffer buffer) {
029: this .buffer = buffer;
030: this .nextWindow = this ;
031: this .prevWindow = this ;
032: }
033:
034: public static EWindow getSelected() {
035: return EFrame.selectedFrame == null ? null
036: : EFrame.selectedFrame.selectedWindow;
037: }
038:
039: public void setSelected() {
040: EWindow selected = getSelected();
041: if (selected != null && selected.buffer != buffer)
042: selected.unselect();
043:
044: if (frame != null)
045: frame.selectedWindow = this ;
046: EFrame.selectedFrame = frame;
047: Buffer.setCurrent(buffer);
048:
049: }
050:
051: public abstract void unselect();
052:
053: public static void setSelected(EWindow window) {
054: window.setSelected();
055: window.requestFocus();
056: }
057:
058: public void requestFocus() {
059: }
060:
061: public EFrame getFrame() {
062: return frame;
063: }
064:
065: public final void setFrame(EFrame frame) {
066: this .frame = frame;
067: }
068:
069: public Buffer getBuffer() {
070: return buffer;
071: }
072:
073: public void setBuffer(Buffer buffer) {
074: this .buffer = buffer;
075: }
076:
077: /** Returns the "Emacs value" (1-origin) of point. */
078: public abstract int getPoint();
079:
080: public final void setPoint(int point) {
081: setDot(point - 1);
082: }
083:
084: public abstract void setDot(int offset);
085:
086: /** Split this window into two, showing this buffer in both windows.
087: * @return the new wndow.
088: */
089: public final EWindow split(int lines, boolean horizontal) {
090: return split(buffer, lines, horizontal);
091: }
092:
093: /** Split this window into two.
094: * Display Var>buffer</var> in the new window.
095: * @return the new window.
096: */
097: public abstract EWindow split(Buffer buffer, int lines,
098: boolean horizontal);
099:
100: /** Link a new window after this. */
101: protected final void linkSibling(EWindow window, boolean horizontal) {
102: this .nextWindow = window;
103: window.prevWindow = this ;
104: EWindow next = nextWindow;
105: window.nextWindow = next;
106: // next is non-null, since the order is cyclic.
107: next.prevWindow = window;
108: }
109:
110: protected final void unlink() {
111: if (frame.firstWindow == this ) {
112: if (nextWindow == this )
113: frame.firstWindow = null;
114: else
115: frame.firstWindow = nextWindow;
116: }
117: nextWindow.prevWindow = prevWindow;
118: prevWindow.nextWindow = nextWindow;
119: prevWindow = this ;
120: nextWindow = this ;
121: }
122:
123: /** Return the next/previous window in the cyclic order of windows.
124: * Returns null if this is the last/first window in this EFrame. */
125: public EWindow getNextWindow(boolean forwards) {
126: return nextWindow;
127: }
128:
129: /** Return the next/previous EWindow in the cyclic order of windows.
130: * Returns first/last if this is the last/first window in this EFrame. */
131: public final EWindow getOtherWindow(boolean forwards) {
132: EWindow win = getNextWindow(forwards); // FIXME
133: /*
134: if (win == null)
135: win = forwards ? frame.getFirstWindow() : frame.getLastWindow();
136: */
137: return win;
138: }
139:
140: public final EWindow getNextWindowInFrame(int count) {
141: EWindow win = this ;
142: if (count > 0) {
143: while (--count >= 0)
144: win = win.getOtherWindow(true);
145: } else {
146: while (++count <= 0)
147: win = win.getOtherWindow(false);
148: }
149: return win;
150: }
151:
152: public void delete() {
153: EFrame frame = this .frame;
154: deleteNoValidate();
155: if (frame.getFirstWindow() == null)
156: frame.delete();
157: else
158: frame.validate();
159: }
160:
161: protected void deleteNoValidate() {
162: if (frame.selectedWindow == this ) {
163: EWindow next = getNextWindowInFrame(1);
164: if (frame == EFrame.selectedFrame)
165: setSelected(next);
166: else
167: frame.selectedWindow = next;
168: }
169: unlink();
170: frame = null;
171: }
172:
173: public void deleteOtherWindows() {
174: for (EWindow cur = frame.getFirstWindow(); cur != null;) {
175: EWindow next = cur.getNextWindow(true);
176: if (cur != this )
177: cur.deleteNoValidate();
178: cur = next;
179: }
180: frame.validate();
181: }
182:
183: protected abstract void getCharSize();
184:
185: /** Get the current width (in pixels) of this window. */
186: public abstract int getWidth();
187:
188: /** Get the current height (in pixels) of this window. */
189: public abstract int getHeight();
190:
191: public int getHeightInLines() {
192: if (charHeight == 0)
193: getCharSize();
194: return getHeight() / charHeight;
195: }
196:
197: public int getWidthInColumns() {
198: if (charWidth == 0)
199: getCharSize();
200: return getWidth() / charWidth;
201: }
202:
203: public String toString() {
204: StringBuffer sbuf = new StringBuffer(100);
205: sbuf.append("#<window on ");
206: if (buffer == null)
207: sbuf.append("no buffer");
208: else {
209: sbuf.append('\"');
210: sbuf.append(buffer.getName());
211: sbuf.append('\"');
212: }
213: sbuf.append(" 0x");
214: sbuf.append(Integer.toHexString(System.identityHashCode(this )));
215: sbuf.append('>');
216: return sbuf.toString();
217: }
218:
219: public void pushPrefix(int prefix) {
220: if (pendingKeys == null)
221: pendingKeys = new int[10];
222: pendingKeys[pendingLength++] = prefix;
223: }
224:
225: public Object lookupKey(int key) {
226: for (int j = 0; j < buffer.activeLength; j++) {
227: EKeymap actual = buffer.activeKeymaps[j];
228: Object action = actual.lookupKey(pendingKeys,
229: pendingLength, key, j < buffer.activeLength - 1);
230: if (action != null)
231: return action;
232: }
233: return EKeymap.ignorable(key) ? null : tooLong(pendingLength);
234: }
235:
236: public abstract Object tooLong(int pendingLength);
237:
238: public void handleKey(int code) {
239: Object command = lookupKey(code);
240:
241: pushPrefix(code);
242: pendingLength--;
243: handleCommand(command);
244: }
245:
246: public void handleCommand(Object command) {
247: if (command instanceof String || command instanceof Symbol) {
248: Object resolved = Command.resolveSymbol(command);
249: if (resolved == null)
250: throw new Error("no function defined for " + command);
251: command = resolved;
252: }
253:
254: if (command instanceof EKeymap) {
255: if (pendingKeys[pendingLength] != 0)
256: pendingLength++;
257: return;
258: }
259:
260: pendingLength = 0;
261:
262: try {
263: Procedure proc = (Procedure) command;
264: Object interactive = proc.getProperty("emacs-interactive",
265: null);
266: if (interactive != null) {
267: if (interactive instanceof String) {
268: proc.applyN(Command
269: .processInteractionString(interactive
270: .toString()));
271: } else if (interactive == LList.Empty)
272: proc.apply0();
273: else {
274: System.err
275: .println("not implemented: interactive not a string");
276: proc.apply0();
277: }
278: } else {
279: // System.err.println("procedure "+proc+" is not interactive");
280: proc.apply0();
281: }
282: } catch (CancelledException ex) {
283: // Do nothing.
284: } catch (RuntimeException ex) {
285: throw ex;
286: } catch (Error ex) {
287: throw ex;
288: } catch (Throwable ex) {
289: throw new WrappedException(ex);
290: }
291:
292: }
293: }
|