OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [swing/] [undo/] [UndoManager.java] - Blame information for rev 775

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 772 jeremybenn
/* UndoManager.java --
2
   Copyright (C) 2002, 2004, 2005, 2006,  Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package javax.swing.undo;
40
 
41
import javax.swing.UIManager;
42
import javax.swing.event.UndoableEditEvent;
43
import javax.swing.event.UndoableEditListener;
44
 
45
 
46
/**
47
 * A manager for providing an application’s undo/redo
48
 * functionality.
49
 *
50
 * <p>Tyipcally, an application will create only one single instance
51
 * of UndoManager. When the user performs an undoable action, for
52
 * instance changing the color of an object from green to blue, the
53
 * application registers an {@link UndoableEdit} object with the
54
 * <code>UndoManager</code>. To implement the &#x201c;undo&#x201d; and
55
 * &#x201c;redo&#x201d; menu commands, the application invokes the
56
 * UndoManager&#x2019;s {@link #undo} and {@link #redo} methods.  The
57
 * human-readable text of these menu commands is provided by {@link
58
 * #getUndoPresentationName} and {@link #getRedoPresentationName},
59
 * respectively. To determine whether the menu item should be
60
 * selectable or greyed out, use {@link #canUndo} and {@link
61
 * #canRedo}.
62
 *
63
 * <p>The UndoManager will only keep a specified number of editing
64
 * actions, the <em>limit</em>. The value of this parameter can be
65
 * retrieved by calling {@link #getLimit} and set with {@link
66
 * #setLimit}.  If more UndoableEdits are added to the UndoManager,
67
 * the oldest actions will be discarded.
68
 *
69
 * <p>Some applications do not provide separate menu commands for
70
 * &#x201c;undo&#x201d; and &#x201c;redo.&#x201d; Instead, they
71
 * have just a single command whose text switches between the two.
72
 * Such applications would use an UndoManager with a <code>limit</code>
73
 * of 1. The text of this combined menu item is available via
74
 * {@link #getUndoOrRedoPresentationName}, and it is implemented
75
 * by calling {@link #undoOrRedo}.
76
 *
77
 * <p><b>Thread Safety:</b> In constrast to the other classes of the
78
 * <code>javax.swing.undo</code> package, the public methods of an
79
 * <code>UndoManager</code> are safe to call from concurrent threads.
80
 * The caller does not need to perform external synchronization, and
81
 * {@link javax.swing.event.UndoableEditEvent} sources do not need to
82
 * broadcast their events from inside the Swing worker thread.
83
 *
84
 * @author Sascha Brawer (brawer@dandelis.ch)
85
 */
86
public class UndoManager
87
  extends CompoundEdit
88
  implements UndoableEditListener
89
{
90
  /**
91
   * The unique ID for serializing instances of this class. Determined
92
   * using the <code>serialver</code> tool of Sun JDK 1.4.1_01 on
93
   * GNU/Linux.
94
   */
95
  static final long serialVersionUID = -2077529998244066750L;
96
 
97
 
98
  /**
99
   * An index into the inherited {@link #edits} Vector that indicates
100
   * at which position newly added editing actions would get inserted.
101
   *
102
   * <p>Normally, the value of <code>indexOfNextAdd</code> equals
103
   * the number of UndoableEdits stored by this UndoManager, i.e.
104
   * <code>edits.size()</code>. For each call to {@link #undo},
105
   * <code>indexOfNextAdd</code> is decremented by one. For each
106
   * call to {@link #redo}, it is incremented again.
107
   */
108
  int indexOfNextAdd;
109
 
110
 
111
  /**
112
   * The maximum number of UndoableEdits stored by this UndoManager.
113
   */
114
  int limit;
115
 
116
 
117
  /**
118
   * Constructs an UndoManager.
119
   *
120
   * <p>The <code>limit</code> of the freshly constructed UndoManager
121
   * is 100.
122
   */
123
  public UndoManager()
124
  {
125
    limit = 100;
126
  }
127
 
128
 
129
  /**
130
   * Returns a string representation for this UndoManager. This may be
131
   * useful for debugging purposes. For the text of menu items, please
132
   * refer to {@link #getUndoPresentationName}, {@link
133
   * #getRedoPresentationName}, and {@link
134
   * #getUndoOrRedoPresentationName}.
135
   */
136
  public String toString()
137
  {
138
    return super.toString()
139
      + " limit: " + limit
140
      + " indexOfNextAdd: " + indexOfNextAdd;
141
  }
142
 
143
 
144
  /**
145
   * Puts this UndoManager into a state where it acts as a normal
146
   * {@link CompoundEdit}. It is unlikely that an application would
147
   * want to do this.
148
   */
149
  public synchronized void end()
150
  {
151
    super.end();
152
    trimEdits(indexOfNextAdd, edits.size() - 1);
153
  }
154
 
155
 
156
  /**
157
   * Returns how many edits this UndoManager can maximally hold.
158
   *
159
   * @see #setLimit
160
   */
161
  public synchronized int getLimit()
162
  {
163
    return limit;
164
  }
165
 
166
 
167
  /**
168
   * Changes the maximal number of edits that this UndoManager can
169
   * process. If there are currently more edits than the new limit
170
   * allows, they will receive a {@link UndoableEdit#die() die}
171
   * message in reverse order of addition.
172
   *
173
   * @param limit the new limit.
174
   *
175
   * @throws IllegalStateException if {@link #end()} has already been
176
   * called on this UndoManager.
177
   */
178
  public synchronized void setLimit(int limit)
179
  {
180
    if (!isInProgress())
181
      throw new IllegalStateException();
182
 
183
    this.limit = limit;
184
    trimForLimit();
185
  }
186
 
187
 
188
  /**
189
   * Discards all editing actions that are currently registered with
190
   * this UndoManager. Each {@link UndoableEdit} will receive a {@link
191
   * UndoableEdit#die() die message}.
192
   */
193
  public synchronized void discardAllEdits()
194
  {
195
    int size;
196
 
197
    size = edits.size();
198
    for (int i = size - 1; i >= 0; i--)
199
      edits.get(i).die();
200
    indexOfNextAdd = 0;
201
    edits.clear();
202
  }
203
 
204
 
205
  /**
206
   * Called by various internal methods in order to enforce
207
   * the <code>limit</code> value.
208
   */
209
  protected void trimForLimit()
210
  {
211
    int high, s;
212
 
213
    s = edits.size();
214
 
215
    /* The Sun J2SE1.4.1_01 implementation can be observed to do
216
     * nothing (instead of throwing an exception) with a negative or
217
     * zero limit. It may be debatable whether this is the best
218
     * behavior, but we replicate it for sake of compatibility.
219
     */
220
    if (limit <= 0 || s <= limit)
221
      return;
222
 
223
    high = Math.min(indexOfNextAdd + limit/2 - 1, s - 1);
224
    trimEdits(high + 1, s - 1);
225
    trimEdits(0, high - limit);
226
  }
227
 
228
 
229
  /**
230
   * Discards a range of edits. All edits in the range <code>[from
231
   * .. to]</code> will receive a {@linkplain UndoableEdit#die() die
232
   * message} before being removed from the edits array.  If
233
   * <code>from</code> is greater than <code>to</code>, nothing
234
   * happens.
235
   *
236
   * @param from the lower bound of the range of edits to be
237
   * discarded.
238
   *
239
   * @param to the upper bound of the range of edits to be discarded.
240
   */
241
  protected void trimEdits(int from, int to)
242
  {
243
    if (from > to)
244
      return;
245
 
246
    for (int i = to; i >= from; i--)
247
        edits.get(i).die();
248
 
249
    // Remove the range [from .. to] from edits. If from == to, which
250
    // is likely to be a very common case, we can do better than
251
    // creating a sub-list and clearing it.
252
    if (to == from)
253
      edits.remove(from);
254
    else
255
      edits.subList(from, to + 1).clear();
256
 
257
    if (indexOfNextAdd > to)
258
      indexOfNextAdd = indexOfNextAdd - to + from - 1;
259
    else if (indexOfNextAdd >= from)
260
      indexOfNextAdd = from;
261
  }
262
 
263
 
264
  /**
265
   * Determines which significant edit would be undone if {@link
266
   * #undo()} was called.
267
   *
268
   * @return the significant edit that would be undone, or
269
   * <code>null</code> if no significant edit would be affected by
270
   * calling {@link #undo()}.
271
   */
272
  protected UndoableEdit editToBeUndone()
273
  {
274
    UndoableEdit result;
275
 
276
    for (int i = indexOfNextAdd - 1; i >= 0; i--)
277
      {
278
        result = edits.get(i);
279
        if (result.isSignificant())
280
          return result;
281
      }
282
 
283
    return null;
284
  }
285
 
286
 
287
  /**
288
   * Determines which significant edit would be redone if {@link
289
   * #redo()} was called.
290
   *
291
   * @return the significant edit that would be redone, or
292
   * <code>null</code> if no significant edit would be affected by
293
   * calling {@link #redo()}.
294
   */
295
  protected UndoableEdit editToBeRedone()
296
  {
297
    UndoableEdit result;
298
 
299
    for (int i = indexOfNextAdd; i < edits.size(); i++)
300
      {
301
        result = edits.get(i);
302
        if (result.isSignificant())
303
          return result;
304
      }
305
 
306
    return null;
307
  }
308
 
309
 
310
  /**
311
   * Undoes all editing actions in reverse order of addition,
312
   * up to the specified action,
313
   *
314
   * @param edit the last editing action to be undone.
315
   */
316
  protected void undoTo(UndoableEdit edit)
317
    throws CannotUndoException
318
  {
319
    UndoableEdit cur;
320
 
321
    if (!edits.contains(edit))
322
      throw new CannotUndoException();
323
 
324
    while (true)
325
      {
326
        indexOfNextAdd -= 1;
327
        cur = edits.get(indexOfNextAdd);
328
        cur.undo();
329
        if (cur == edit)
330
          return;
331
      }
332
  }
333
 
334
 
335
  /**
336
   * Redoes all editing actions in the same order as they were
337
   * added to this UndoManager, up to the specified action.
338
   *
339
   * @param edit the last editing action to be redone.
340
   */
341
  protected void redoTo(UndoableEdit edit)
342
    throws CannotRedoException
343
  {
344
    UndoableEdit cur;
345
 
346
    if (!edits.contains(edit))
347
      throw new CannotRedoException();
348
 
349
    while (true)
350
      {
351
        cur = edits.get(indexOfNextAdd);
352
        indexOfNextAdd += 1;
353
        cur.redo();
354
        if (cur == edit)
355
          return;
356
      }
357
  }
358
 
359
 
360
  /**
361
   * Undoes or redoes the last action. If the last action has already
362
   * been undone, it will be re-done, and vice versa.
363
   *
364
   * <p>This is useful for applications that do not present a separate
365
   * undo and redo facility, but just have a single menu item for
366
   * undoing and redoing the very last action. Such applications will
367
   * use an <code>UndoManager</code> whose <code>limit</code> is 1.
368
   */
369
  public synchronized void undoOrRedo()
370
    throws CannotRedoException, CannotUndoException
371
  {
372
    if (indexOfNextAdd == edits.size())
373
      undo();
374
    else
375
      redo();
376
  }
377
 
378
 
379
  /**
380
   * Determines whether it would be possible to either undo or redo
381
   * this editing action.
382
   *
383
   * <p>This is useful for applications that do not present a separate
384
   * undo and redo facility, but just have a single menu item for
385
   * undoing and redoing the very last action. Such applications will
386
   * use an <code>UndoManager</code> whose <code>limit</code> is 1.
387
   *
388
   * @return <code>true</code> to indicate that this action can be
389
   * undone or redone; <code>false</code> if neither is possible at
390
   * the current time.
391
   */
392
  public synchronized boolean canUndoOrRedo()
393
  {
394
    return indexOfNextAdd == edits.size() ? canUndo() : canRedo();
395
  }
396
 
397
 
398
  /**
399
   * Undoes one significant edit action. If insignificant actions have
400
   * been posted after the last signficant action, the insignificant
401
   * ones will be undone first.
402
   *
403
   * <p>However, if {@link #end()} has been called on this
404
   * UndoManager, it will behave like a normal {@link
405
   * CompoundEdit}. In this case, all actions will be undone in
406
   * reverse order of addition. Typical applications will never call
407
   * {@link #end()} on their <code>UndoManager</code>.
408
   *
409
   * @throws CannotUndoException if no action can be undone.
410
   *
411
   * @see #canUndo()
412
   * @see #redo()
413
   * @see #undoOrRedo()
414
   */
415
  public synchronized void undo()
416
    throws CannotUndoException
417
  {
418
    if (!isInProgress())
419
      {
420
        super.undo();
421
        return;
422
      }
423
 
424
    UndoableEdit edit = editToBeUndone();
425
    if (edit == null)
426
      throw new CannotUndoException();
427
 
428
    undoTo(edit);
429
  }
430
 
431
 
432
  /**
433
   * Determines whether it would be possible to undo this editing
434
   * action.
435
   *
436
   * @return <code>true</code> to indicate that this action can be
437
   * undone; <code>false</code> otherwise.
438
   *
439
   * @see #undo()
440
   * @see #canRedo()
441
   * @see #canUndoOrRedo()
442
   */
443
  public synchronized boolean canUndo()
444
  {
445
    UndoableEdit edit;
446
 
447
    if (!isInProgress())
448
      return super.canUndo();
449
 
450
    edit = editToBeUndone();
451
    return edit != null && edit.canUndo();
452
  }
453
 
454
 
455
 
456
  /**
457
   * Redoes one significant edit action. If insignificant actions have
458
   * been posted in between, the insignificant ones will be redone
459
   * first.
460
   *
461
   * <p>However, if {@link #end()} has been called on this
462
   * UndoManager, it will behave like a normal {@link
463
   * CompoundEdit}. In this case, <em>all</em> actions will be redone
464
   * in order of addition. Typical applications will never call {@link
465
   * #end()} on their <code>UndoManager</code>.
466
   *
467
   * @throws CannotRedoException if no action can be redone.
468
   *
469
   * @see #canRedo()
470
   * @see #redo()
471
   * @see #undoOrRedo()
472
   */
473
  public synchronized void redo()
474
    throws CannotRedoException
475
  {
476
    if (!isInProgress())
477
      {
478
        super.redo();
479
        return;
480
      }
481
 
482
    UndoableEdit edit = editToBeRedone();
483
    if (edit == null)
484
      throw new CannotRedoException();
485
 
486
    redoTo(edit);
487
  }
488
 
489
 
490
  /**
491
   * Determines whether it would be possible to redo this editing
492
   * action.
493
   *
494
   * @return <code>true</code> to indicate that this action can be
495
   * redone; <code>false</code> otherwise.
496
   *
497
   * @see #redo()
498
   * @see #canUndo()
499
   * @see #canUndoOrRedo()
500
   */
501
  public synchronized boolean canRedo()
502
  {
503
    UndoableEdit edit;
504
 
505
    if (!isInProgress())
506
      return super.canRedo();
507
 
508
    edit = editToBeRedone();
509
    return edit != null && edit.canRedo();
510
  }
511
 
512
 
513
  /**
514
   * Registers an undoable editing action with this UndoManager.  If
515
   * the capacity <code>limit</code> is reached, the oldest action
516
   * will be discarded (and receives a {@linkplain UndoableEdit#die()
517
   * die message}. Equally, any actions that were undone (but not re-done)
518
   * will be discarded, too.
519
   *
520
   * @param edit the editing action that is added to this UndoManager.
521
   *
522
   * @return <code>true</code> if <code>edit</code> could be
523
   * incorporated; <code>false</code> if <code>edit</code> has not
524
   * been incorporated because {@link #end()} has already been called
525
   * on this <code>UndoManager</code>.
526
   */
527
  public synchronized boolean addEdit(UndoableEdit edit)
528
  {
529
    boolean result;
530
 
531
    // Discard any edits starting at indexOfNextAdd.
532
    trimEdits(indexOfNextAdd, edits.size() - 1);
533
 
534
    result = super.addEdit(edit);
535
    indexOfNextAdd = edits.size();
536
    trimForLimit();
537
    return result;
538
  }
539
 
540
 
541
  /**
542
   * Calculates a localized text for presenting the undo or redo
543
   * action to the user, for example in the form of a menu command.
544
   *
545
   * <p>This is useful for applications that do not present a separate
546
   * undo and redo facility, but just have a single menu item for
547
   * undoing and redoing the very last action. Such applications will
548
   * use an <code>UndoManager</code> whose <code>limit</code> is 1.
549
   *
550
   * @return the redo presentation name if the last action has already
551
   * been undone, or the undo presentation name otherwise.
552
   *
553
   * @see #getUndoPresentationName()
554
   * @see #getRedoPresentationName()
555
   */
556
  public synchronized String getUndoOrRedoPresentationName()
557
  {
558
    if (indexOfNextAdd == edits.size())
559
      return getUndoPresentationName();
560
    else
561
      return getRedoPresentationName();
562
  }
563
 
564
 
565
  /**
566
   * Calculates a localized text for presenting the undo action
567
   * to the user, for example in the form of a menu command.
568
   */
569
  public synchronized String getUndoPresentationName()
570
  {
571
    UndoableEdit edit;
572
 
573
    if (!isInProgress())
574
      return super.getUndoPresentationName();
575
 
576
    edit = editToBeUndone();
577
    if (edit == null)
578
      return UIManager.getString("AbstractUndoableEdit.undoText");
579
    else
580
      return edit.getUndoPresentationName();
581
  }
582
 
583
 
584
  /**
585
   * Calculates a localized text for presenting the redo action
586
   * to the user, for example in the form of a menu command.
587
   */
588
  public synchronized String getRedoPresentationName()
589
  {
590
    UndoableEdit edit;
591
 
592
    if (!isInProgress())
593
      return super.getRedoPresentationName();
594
 
595
    edit = editToBeRedone();
596
    if (edit == null)
597
      return UIManager.getString("AbstractUndoableEdit.redoText");
598
    else
599
      return edit.getRedoPresentationName();
600
  }
601
 
602
 
603
  /**
604
   * Registers the edit action of an {@link UndoableEditEvent}
605
   * with this UndoManager.
606
   *
607
   * <p><b>Thread Safety:</b> This method may safely be invoked from
608
   * concurrent threads.  The caller does not need to perform external
609
   * synchronization. This means that {@link
610
   * javax.swing.event.UndoableEditEvent} sources do not need to broadcast
611
   * their events from inside the Swing worker thread.
612
   *
613
   * @param event the event whose <code>edit</code> will be
614
   * passed to {@link #addEdit}.
615
   *
616
   * @see UndoableEditEvent#getEdit()
617
   * @see #addEdit
618
   */
619
  public void undoableEditHappened(UndoableEditEvent event)
620
  {
621
    // Note that this method does not need to be synchronized,
622
    // because addEdit will obtain and release the mutex.
623
    addEdit(event.getEdit());
624
  }
625
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.