Skip to content

Package: ProgressCompoundCommand

ProgressCompoundCommand

nameinstructionbranchcomplexitylinemethod
ProgressCompoundCommand(int, IProgressMonitorProvider)
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
append(Command)
M: 16 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
appendAndExecute(Command)
M: 57 C: 0
0%
M: 10 C: 0
0%
M: 6 C: 0
0%
M: 21 C: 0
0%
M: 1 C: 0
0%
appendIfCanExecute(Command)
M: 18 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
canUndo()
M: 19 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
dispose()
M: 15 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
execute()
M: 51 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 17 C: 0
0%
M: 1 C: 0
0%
getAffectedObjects()
M: 44 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
getCommandList()
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getDescription()
M: 51 C: 0
0%
M: 10 C: 0
0%
M: 6 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
getLabel()
M: 51 C: 0
0%
M: 10 C: 0
0%
M: 6 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
getMergedAffectedObjectsCollection()
M: 23 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
getMergedResultCollection()
M: 23 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
getResult()
M: 44 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
getResultIndex()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
isEmpty()
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
prepare()
M: 25 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
redo()
M: 48 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 16 C: 0
0%
M: 1 C: 0
0%
toString()
M: 36 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
undo()
M: 51 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 17 C: 0
0%
M: 1 C: 0
0%
unwrap()
M: 20 C: 0
0%
M: 3 C: 0
0%
M: 3 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
worked()
M: 14 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH and others.
3: *
4: * All rights reserved. This program and the accompanying materials
5: * are made available under the terms of the Eclipse Public License 2.0
6: * which accompanies this distribution, and is available at
7: * https://www.eclipse.org/legal/epl-2.0/
8: *
9: * SPDX-License-Identifier: EPL-2.0
10: *
11: * Contributors:
12: * Johannes Faltermeier - initial API and implementation
13: ******************************************************************************/
14: package org.eclipse.emf.ecp.edit.spi.swt.commands;
15:
16: import java.util.ArrayList;
17: import java.util.Collection;
18: import java.util.Collections;
19: import java.util.List;
20: import java.util.ListIterator;
21:
22: import org.eclipse.core.runtime.IProgressMonitor;
23: import org.eclipse.emf.common.CommonPlugin;
24: import org.eclipse.emf.common.command.Command;
25: import org.eclipse.emf.common.command.CompoundCommand;
26: import org.eclipse.emf.common.command.UnexecutableCommand;
27: import org.eclipse.emf.common.util.WrappedException;
28: import org.eclipse.swt.widgets.Display;
29:
30: /**
31: * Extension of the {@link CompoundCommand} which reports progress.
32: *
33: * @author Johannes Faltermeier
34: * @since 1.11
35: *
36: */
37: public class ProgressCompoundCommand extends CompoundCommand {
38:
39:         private final IProgressMonitorProvider monitor;
40:
41:         /**
42:          * Creates an empty instance with the given result index.
43:          *
44:          * @param resultIndex the {@link #resultIndex}.
45:          * @param monitor the progress monitor
46:          */
47:         public ProgressCompoundCommand(int resultIndex, IProgressMonitorProvider monitor) {
48:                 super(resultIndex);
49:                 this.monitor = monitor;
50:         }
51:
52:         // REUSED CLASS
53:
54:         /**
55:          * Returns whether there are commands in the list.
56:          *
57:          * @return whether there are commands in the list.
58:          */
59:         @Override
60:         public boolean isEmpty() {
61:                 return commandList.isEmpty();
62:         }
63:
64:         /**
65:          * Returns an unmodifiable view of the commands in the list.
66:          *
67:          * @return an unmodifiable view of the commands in the list.
68:          */
69:         @Override
70:         public List<Command> getCommandList() {
71:                 return Collections.unmodifiableList(commandList);
72:         }
73:
74:         /**
75:          * Returns the index of the command whose result and affected objects are forwarded.
76:          * Negative values have special meaning, as defined by the static constants.
77:          *
78:          * @return the index of the command whose result and affected objects are forwarded.
79:          * @see #LAST_COMMAND_ALL
80:          * @see #MERGE_COMMAND_ALL
81:          */
82:         @Override
83:         public int getResultIndex() {
84:                 return resultIndex;
85:         }
86:
87:         /**
88:          * Returns whether all the commands can execute so that {@link #isExecutable} can be cached.
89:          * An empty command list causes <code>false</code> to be returned.
90:          *
91:          * @return whether all the commands can execute.
92:          */
93:         @Override
94:         protected boolean prepare() {
95:•                if (commandList.isEmpty()) {
96:                         return false;
97:                 }
98:•                for (final Command command : commandList) {
99:•                        if (!command.canExecute()) {
100:                                 return false;
101:                         }
102:                 }
103:
104:                 return true;
105:         }
106:
107:         /**
108:          * Calls {@link Command#execute} for each command in the list.
109:          */
110:         @Override
111:         public void execute() {
112:•                for (final ListIterator<Command> commands = commandList.listIterator(); commands.hasNext();) {
113:                         try {
114:                                 final Command command = commands.next();
115:                                 command.execute();
116:                                 worked();
117:                         } catch (final RuntimeException exception) {
118:                                 // Skip over the command that threw the exception.
119:                                 //
120:                                 commands.previous();
121:
122:                                 try {
123:                                         // Iterate back over the executed commands to undo them.
124:                                         //
125:•                                        while (commands.hasPrevious()) {
126:                                                 final Command command = commands.previous();
127:•                                                if (command.canUndo()) {
128:                                                         command.undo();
129:                                                         worked();
130:                                                 } else {
131:                                                         break;
132:                                                 }
133:                                         }
134:                                 } catch (final RuntimeException nestedException) {
135:                                         CommonPlugin.INSTANCE
136:                                                 .log(new WrappedException(CommonPlugin.INSTANCE.getString("_UI_IgnoreException_exception"), //$NON-NLS-1$
137:                                                         nestedException).fillInStackTrace());
138:                                 }
139:
140:                                 throw exception;
141:                         }
142:                 }
143:         }
144:
145:         /**
146:          * Returns <code>false</code> if any of the commands return <code>false</code> for {@link Command#canUndo}.
147:          *
148:          * @return <code>false</code> if any of the commands return <code>false</code> for <code>canUndo</code>.
149:          */
150:         @Override
151:         public boolean canUndo() {
152:•                for (final Command command : commandList) {
153:•                        if (!command.canUndo()) {
154:                                 return false;
155:                         }
156:                 }
157:
158:                 return true;
159:         }
160:
161:         /**
162:          * Calls {@link Command#undo} for each command in the list, in reverse order.
163:          */
164:         @Override
165:         public void undo() {
166:                 for (final ListIterator<Command> commands = commandList.listIterator(commandList.size()); commands
167:•                        .hasPrevious();) {
168:                         try {
169:                                 final Command command = commands.previous();
170:                                 command.undo();
171:                                 worked();
172:                         } catch (final RuntimeException exception) {
173:                                 // Skip over the command that threw the exception.
174:                                 //
175:                                 commands.next();
176:
177:                                 try {
178:                                         // Iterate forward over the undone commands to redo them.
179:                                         //
180:•                                        while (commands.hasNext()) {
181:                                                 final Command command = commands.next();
182:                                                 command.redo();
183:                                                 worked();
184:                                         }
185:                                 } catch (final RuntimeException nestedException) {
186:                                         CommonPlugin.INSTANCE
187:                                                 .log(new WrappedException(CommonPlugin.INSTANCE.getString("_UI_IgnoreException_exception"), //$NON-NLS-1$
188:                                                         nestedException).fillInStackTrace());
189:                                 }
190:
191:                                 throw exception;
192:                         }
193:                 }
194:         }
195:
196:         /**
197:          * Calls {@link Command#redo} for each command in the list.
198:          */
199:         @Override
200:         public void redo() {
201:•                for (final ListIterator<Command> commands = commandList.listIterator(); commands.hasNext();) {
202:                         try {
203:                                 final Command command = commands.next();
204:                                 command.redo();
205:                                 worked();
206:                         } catch (final RuntimeException exception) {
207:                                 // Skip over the command that threw the exception.
208:                                 //
209:                                 commands.previous();
210:
211:                                 try {
212:                                         // Iterate back over the executed commands to undo them.
213:                                         //
214:•                                        while (commands.hasPrevious()) {
215:                                                 final Command command = commands.previous();
216:                                                 command.undo();
217:                                                 worked();
218:                                         }
219:                                 } catch (final RuntimeException nestedException) {
220:                                         CommonPlugin.INSTANCE
221:                                                 .log(new WrappedException(CommonPlugin.INSTANCE.getString("_UI_IgnoreException_exception"), //$NON-NLS-1$
222:                                                         nestedException).fillInStackTrace());
223:                                 }
224:
225:                                 throw exception;
226:                         }
227:                 }
228:         }
229:
230:         /**
231:          * Determines the result by composing the results of the commands in the list;
232:          * this is affected by the setting of {@link #resultIndex}.
233:          *
234:          * @return the result.
235:          */
236:         @Override
237:         public Collection<?> getResult() {
238:•                if (commandList.isEmpty()) {
239:                         return Collections.EMPTY_LIST;
240:•                } else if (resultIndex == LAST_COMMAND_ALL) {
241:                         return commandList.get(commandList.size() - 1).getResult();
242:•                } else if (resultIndex == MERGE_COMMAND_ALL) {
243:                         return getMergedResultCollection();
244:•                } else if (resultIndex < commandList.size()) {
245:                         return commandList.get(resultIndex).getResult();
246:                 } else {
247:                         return Collections.EMPTY_LIST;
248:                 }
249:         }
250:
251:         /**
252:          * Returns the merged collection of all command results.
253:          *
254:          * @return the merged collection of all command results.
255:          */
256:         @Override
257:         protected Collection<?> getMergedResultCollection() {
258:                 final Collection<Object> result = new ArrayList<Object>();
259:
260:•                for (final Command command : commandList) {
261:                         result.addAll(command.getResult());
262:                 }
263:
264:                 return result;
265:         }
266:
267:         /**
268:          * Determines the affected objects by composing the affected objects of the commands in the list;
269:          * this is affected by the setting of {@link #resultIndex}.
270:          *
271:          * @return the affected objects.
272:          */
273:         @Override
274:         public Collection<?> getAffectedObjects() {
275:•                if (commandList.isEmpty()) {
276:                         return Collections.EMPTY_LIST;
277:•                } else if (resultIndex == LAST_COMMAND_ALL) {
278:                         return commandList.get(commandList.size() - 1).getAffectedObjects();
279:•                } else if (resultIndex == MERGE_COMMAND_ALL) {
280:                         return getMergedAffectedObjectsCollection();
281:•                } else if (resultIndex < commandList.size()) {
282:                         return commandList.get(resultIndex).getAffectedObjects();
283:                 } else {
284:                         return Collections.EMPTY_LIST;
285:                 }
286:         }
287:
288:         /**
289:          * Returns the merged collection of all command affected objects.
290:          *
291:          * @return the merged collection of all command affected objects.
292:          */
293:         @Override
294:         protected Collection<?> getMergedAffectedObjectsCollection() {
295:                 final Collection<Object> result = new ArrayList<Object>();
296:
297:•                for (final Command command : commandList) {
298:                         result.addAll(command.getAffectedObjects());
299:                 }
300:
301:                 return result;
302:         }
303:
304:         /**
305:          * Determines the label by composing the labels of the commands in the list;
306:          * this is affected by the setting of {@link #resultIndex}.
307:          *
308:          * @return the label.
309:          */
310:         @Override
311:         public String getLabel() {
312:•                if (label != null) {
313:                         return label;
314:•                } else if (commandList.isEmpty()) {
315:                         return CommonPlugin.INSTANCE.getString("_UI_CompoundCommand_label"); //$NON-NLS-1$
316:•                } else if (resultIndex == LAST_COMMAND_ALL || resultIndex == MERGE_COMMAND_ALL) {
317:                         return commandList.get(commandList.size() - 1).getLabel();
318:•                } else if (resultIndex < commandList.size()) {
319:                         return commandList.get(resultIndex).getLabel();
320:                 } else {
321:                         return CommonPlugin.INSTANCE.getString("_UI_CompoundCommand_label"); //$NON-NLS-1$
322:                 }
323:         }
324:
325:         /**
326:          * Determines the description by composing the descriptions of the commands in the list;
327:          * this is affected by the setting of {@link #resultIndex}.
328:          *
329:          * @return the description.
330:          */
331:         @Override
332:         public String getDescription() {
333:•                if (description != null) {
334:                         return description;
335:•                } else if (commandList.isEmpty()) {
336:                         return CommonPlugin.INSTANCE.getString("_UI_CompoundCommand_description"); //$NON-NLS-1$
337:•                } else if (resultIndex == LAST_COMMAND_ALL || resultIndex == MERGE_COMMAND_ALL) {
338:                         return commandList.get(commandList.size() - 1).getDescription();
339:•                } else if (resultIndex < commandList.size()) {
340:                         return commandList.get(resultIndex).getDescription();
341:                 } else {
342:                         return CommonPlugin.INSTANCE.getString("_UI_CompoundCommand_description"); //$NON-NLS-1$
343:                 }
344:         }
345:
346:         /**
347:          * Adds a command to this compound command's list of commands.
348:          *
349:          * @param command the command to append.
350:          */
351:         @Override
352:         public void append(Command command) {
353:•                if (isPrepared) {
354:                         throw new IllegalStateException("The command is already prepared"); //$NON-NLS-1$
355:                 }
356:
357:•                if (command != null) {
358:                         commandList.add(command);
359:                 }
360:         }
361:
362:         /**
363:          * Checks if the command can execute;
364:          * if so, it is executed, appended to the list, and true is returned,
365:          * if not, it is just disposed and false is returned.
366:          * A typical use for this is to execute commands created during the execution of another command, e.g.,
367:          *
368:          * <pre>
369:          * class MyCommand extends CommandBase
370:          * {
371:          * protected Command subcommand;
372:          *
373:          * //...
374:          *
375:          * public void execute()
376:          * {
377:          * // ...
378:          * Compound subcommands = new CompoundCommand();
379:          * subcommands.appendAndExecute(new AddCommand(...));
380:          * if (condition) subcommands.appendAndExecute(new AddCommand(...));
381:          * subcommand = subcommands.unwrap();
382:          * }
383:          *
384:          * public void undo()
385:          * {
386:          * // ...
387:          * subcommand.undo();
388:          * }
389:          *
390:          * public void redo()
391:          * {
392:          * // ...
393:          * subcommand.redo();
394:          * }
395:          *
396:          * public void dispose()
397:          * {
398:          * // ...
399:          * if (subcommand != null)
400:          * {
401:          * subcommand.dispose();
402:          * }
403:          * }
404:          * }
405:          * </pre>
406:          *
407:          * Another use is in an execute override of compound command itself:
408:          *
409:          * <pre>
410:          * class MyCommand extends CompoundCommand
411:          * {
412:          * public void execute()
413:          * {
414:          * // ...
415:          * appendAndExecute(new AddCommand(...));
416:          * if (condition) appendAndExecute(new AddCommand(...));
417:          * }
418:          * }
419:          * </pre>
420:          *
421:          * Note that appending commands will modify what getResult and getAffectedObjects return,
422:          * so you may want to set the resultIndex flag.
423:          *
424:          * @param command the command.
425:          * @return whether the command was successfully executed and appended.
426:          */
427:         @Override
428:         public boolean appendAndExecute(Command command) {
429:•                if (command != null) {
430:•                        if (!isPrepared) {
431:•                                if (commandList.isEmpty()) {
432:                                         isPrepared = true;
433:                                         isExecutable = true;
434:                                 } else {
435:                                         isExecutable = prepare();
436:                                         isPrepared = true;
437:•                                        if (isExecutable) {
438:                                                 execute();
439:                                         }
440:                                 }
441:                         }
442:
443:•                        if (command.canExecute()) {
444:                                 try {
445:                                         command.execute();
446:                                         worked();
447:                                         commandList.add(command);
448:                                         return true;
449:                                 } catch (final RuntimeException exception) {
450:                                         CommonPlugin.INSTANCE
451:                                                 .log(new WrappedException(CommonPlugin.INSTANCE.getString("_UI_IgnoreException_exception"), //$NON-NLS-1$
452:                                                         exception).fillInStackTrace());
453:                                 }
454:                         }
455:
456:                         command.dispose();
457:                 }
458:
459:                 return false;
460:         }
461:
462:         /**
463:          * Adds a command to this compound command's the list of commands and returns <code>true</code>,
464:          * if <code>command.{@link org.eclipse.emf.common.command.Command#canExecute() canExecute()}</code> returns true;
465:          * otherwise, it simply calls
466:          * <code>command.{@link org.eclipse.emf.common.command.Command#dispose() dispose()}</code>
467:          * and returns <code>false</code>.
468:          *
469:          * @param command the command.
470:          * @return whether the command was executed and appended.
471:          */
472:         @Override
473:         public boolean appendIfCanExecute(Command command) {
474:•                if (command == null) {
475:                         return false;
476:•                } else if (command.canExecute()) {
477:                         commandList.add(command);
478:                         return true;
479:                 } else {
480:                         command.dispose();
481:                         return false;
482:                 }
483:         }
484:
485:         /**
486:          * Calls {@link Command#dispose} for each command in the list.
487:          */
488:         @Override
489:         public void dispose() {
490:•                for (final Command command : commandList) {
491:                         command.dispose();
492:                 }
493:         }
494:
495:         /**
496:          * Returns one of three things:
497:          * {@link org.eclipse.emf.common.command.UnexecutableCommand#INSTANCE}, if there are no commands,
498:          * the one command, if there is exactly one command,
499:          * or <code>this</code>, if there are multiple commands;
500:          * this command is {@link #dispose}d in the first two cases.
501:          * You should only unwrap a compound command if you created it for that purpose, e.g.,
502:          *
503:          * <pre>
504:          * CompoundCommand subcommands = new CompoundCommand();
505:          * subcommands.append(x);
506:          * if (condition)
507:          *         subcommands.append(y);
508:          * Command result = subcommands.unwrap();
509:          * </pre>
510:          *
511:          * is a good way to create an efficient accumulated result.
512:          *
513:          * @return the unwrapped command.
514:          */
515:         @Override
516:         public Command unwrap() {
517:•                switch (commandList.size()) {
518:                 case 0: {
519:                         dispose();
520:                         return UnexecutableCommand.INSTANCE;
521:                 }
522:                 case 1: {
523:                         final Command result = commandList.remove(0);
524:                         dispose();
525:                         return result;
526:                 }
527:                 default: {
528:                         return this;
529:                 }
530:                 }
531:         }
532:
533:         @Override
534:         public String toString() {
535:                 final StringBuffer result = new StringBuffer(super.toString());
536:                 result.append(" (commandList: #" + commandList.size() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
537:                 result.append(" (resultIndex: " + resultIndex + ")"); //$NON-NLS-1$ //$NON-NLS-2$
538:
539:                 return result.toString();
540:         }
541:
542:         // END REUSED CLASS
543:
544:         private void worked() {
545:                 final IProgressMonitor progressMonitor = monitor.getProgressMonitor();
546:•                if (progressMonitor == null) {
547:                         return;
548:                 }
549:                 progressMonitor.worked(1);
550:•                while (Display.getDefault().readAndDispatch()) {
551:                 }
552:         }
553:
554: }