1 11 package org.eclipse.jdt.internal.ui.refactoring; 12 13 import java.lang.reflect.InvocationTargetException ; 14 import java.util.ArrayList ; 15 import java.util.Arrays ; 16 import java.util.HashMap ; 17 import java.util.Iterator ; 18 import java.util.List ; 19 import java.util.Map ; 20 21 import org.eclipse.core.runtime.Assert; 22 import org.eclipse.core.runtime.IProgressMonitor; 23 24 import org.eclipse.swt.SWT; 25 import org.eclipse.swt.events.SelectionAdapter; 26 import org.eclipse.swt.events.SelectionEvent; 27 import org.eclipse.swt.graphics.Image; 28 import org.eclipse.swt.layout.GridData; 29 import org.eclipse.swt.layout.GridLayout; 30 import org.eclipse.swt.widgets.Button; 31 import org.eclipse.swt.widgets.Composite; 32 import org.eclipse.swt.widgets.Item; 33 import org.eclipse.swt.widgets.Label; 34 import org.eclipse.swt.widgets.Table; 35 import org.eclipse.swt.widgets.TableColumn; 36 37 import org.eclipse.jface.dialogs.Dialog; 38 import org.eclipse.jface.dialogs.IDialogConstants; 39 import org.eclipse.jface.operation.IRunnableWithProgress; 40 import org.eclipse.jface.viewers.ArrayContentProvider; 41 import org.eclipse.jface.viewers.CellEditor; 42 import org.eclipse.jface.viewers.CheckStateChangedEvent; 43 import org.eclipse.jface.viewers.ColumnWeightData; 44 import org.eclipse.jface.viewers.ComboBoxCellEditor; 45 import org.eclipse.jface.viewers.DoubleClickEvent; 46 import org.eclipse.jface.viewers.ICellModifier; 47 import org.eclipse.jface.viewers.ICheckStateListener; 48 import org.eclipse.jface.viewers.IDoubleClickListener; 49 import org.eclipse.jface.viewers.ILabelProvider; 50 import org.eclipse.jface.viewers.ISelection; 51 import org.eclipse.jface.viewers.ISelectionChangedListener; 52 import org.eclipse.jface.viewers.IStructuredSelection; 53 import org.eclipse.jface.viewers.ITableLabelProvider; 54 import org.eclipse.jface.viewers.LabelProvider; 55 import org.eclipse.jface.viewers.SelectionChangedEvent; 56 import org.eclipse.jface.viewers.StructuredSelection; 57 import org.eclipse.jface.viewers.TableLayout; 58 import org.eclipse.jface.window.Window; 59 60 import org.eclipse.ui.PlatformUI; 61 62 import org.eclipse.ltk.ui.refactoring.RefactoringWizard; 63 import org.eclipse.ltk.ui.refactoring.UserInputWizardPage; 64 65 import org.eclipse.jdt.core.IMember; 66 import org.eclipse.jdt.core.JavaModelException; 67 68 import org.eclipse.jdt.internal.corext.refactoring.structure.PushDownRefactoring; 69 import org.eclipse.jdt.internal.corext.refactoring.structure.PushDownRefactoringProcessor.MemberActionInfo; 70 import org.eclipse.jdt.internal.corext.util.Messages; 71 72 import org.eclipse.jdt.ui.JavaElementLabelProvider; 73 74 import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; 75 import org.eclipse.jdt.internal.ui.util.ExceptionHandler; 76 import org.eclipse.jdt.internal.ui.util.PixelConverter; 77 import org.eclipse.jdt.internal.ui.util.SWTUtil; 78 import org.eclipse.jdt.internal.ui.util.TableLayoutComposite; 79 80 public final class PushDownWizard extends RefactoringWizard { 81 82 private static class PushDownInputPage extends UserInputWizardPage { 83 84 private static class MemberActionInfoLabelProvider extends LabelProvider implements ITableLabelProvider { 85 86 private static String getActionLabel(final int action) { 87 switch (action) { 88 case MemberActionInfo.NO_ACTION: 89 return ""; case MemberActionInfo.PUSH_ABSTRACT_ACTION: 91 return RefactoringMessages.PushDownInputPage_leave_abstract; 92 case MemberActionInfo.PUSH_DOWN_ACTION: 93 return RefactoringMessages.PushDownInputPage_push_down; 94 default: 95 Assert.isTrue(false); 96 return null; 97 } 98 } 99 100 private static String [] getAvailableActionLabels(final MemberActionInfo info) { 101 final int[] actions= info.getAvailableActions(); 102 final String [] result= new String [actions.length]; 103 for (int index= 0; index < actions.length; index++) { 104 result[index]= getActionLabel(actions[index]); 105 } 106 return result; 107 } 108 109 private final ILabelProvider fLabelProvider= new JavaElementLabelProvider(JavaElementLabelProvider.SHOW_DEFAULT | JavaElementLabelProvider.SHOW_SMALL_ICONS); 110 111 public void dispose() { 112 fLabelProvider.dispose(); 113 super.dispose(); 114 } 115 116 public Image getColumnImage(final Object element, final int index) { 117 final MemberActionInfo info= (MemberActionInfo) element; 118 switch (index) { 119 case MEMBER_COLUMN: 120 return fLabelProvider.getImage(info.getMember()); 121 case ACTION_COLUMN: 122 return null; 123 default: 124 Assert.isTrue(false); 125 return null; 126 } 127 } 128 129 public String getColumnText(final Object element, final int index) { 130 final MemberActionInfo info= (MemberActionInfo) element; 131 switch (index) { 132 case MEMBER_COLUMN: 133 return fLabelProvider.getText(info.getMember()); 134 case ACTION_COLUMN: 135 return getActionLabel(info.getAction()); 136 default: 137 Assert.isTrue(false); 138 return null; 139 } 140 } 141 } 142 143 private class PushDownCellModifier implements ICellModifier { 144 145 public boolean canModify(final Object element, final String property) { 146 if (!ACTION_PROPERTY.equals(property)) 147 return false; 148 return ((MemberActionInfo) element).isEditable(); 149 } 150 151 public Object getValue(final Object element, final String property) { 152 if (!ACTION_PROPERTY.equals(property)) 153 return null; 154 155 final MemberActionInfo info= (MemberActionInfo) element; 156 return new Integer (info.getAction()); 157 } 158 159 public void modify(final Object element, final String property, final Object value) { 160 if (!ACTION_PROPERTY.equals(property)) 161 return; 162 163 final int action= ((Integer ) value).intValue(); 164 MemberActionInfo info; 165 if (element instanceof Item) { 166 info= (MemberActionInfo) ((Item) element).getData(); 167 } else 168 info= (MemberActionInfo) element; 169 if (!canModify(info, property)) 170 return; 171 info.setAction(action); 172 PushDownInputPage.this.updateWizardPage(null, true); 173 } 174 } 175 176 private static final int ACTION_COLUMN= 1; 177 178 private final static String ACTION_PROPERTY= "action"; 180 private static final int MEMBER_COLUMN= 0; 181 182 private final static String MEMBER_PROPERTY= "member"; 184 private static final String PAGE_NAME= "PushDownInputPage"; 186 private static final int ROW_COUNT= 10; 187 188 private static int countEditableInfos(final MemberActionInfo[] infos) { 189 int result= 0; 190 for (int index= 0; index < infos.length; index++) { 191 if (infos[index].isEditable()) 192 result++; 193 } 194 return result; 195 } 196 197 private static void setInfoAction(final MemberActionInfo[] infos, final int action) { 198 for (int index= 0; index < infos.length; index++) { 199 infos[index].setAction(action); 200 } 201 } 202 203 private Button fDeselectAllButton; 204 205 private Button fEditButton; 206 207 private Button fSelectAllButton; 208 209 private Label fStatusLine; 210 211 private PullPushCheckboxTableViewer fTableViewer; 212 213 public PushDownInputPage() { 214 super(PAGE_NAME); 215 } 216 217 private boolean areAllElementsMarkedAsNoAction() { 218 return countInfosForAction(MemberActionInfo.NO_ACTION) == ((MemberActionInfo[]) fTableViewer.getInput()).length; 219 } 220 221 private boolean areAllElementsMarkedAsPushDownAction() { 222 return countInfosForAction(MemberActionInfo.PUSH_DOWN_ACTION) == ((MemberActionInfo[]) fTableViewer.getInput()).length; 223 } 224 225 private void checkPageCompletionStatus(final boolean displayErrorMessage) { 226 if (areAllElementsMarkedAsNoAction()) { 227 if (displayErrorMessage) 228 setErrorMessage(RefactoringMessages.PushDownInputPage_Select_members_to_push_down); 229 setPageComplete(false); 230 } else { 231 setErrorMessage(null); 232 setPageComplete(true); 233 } 234 } 235 236 private int countInfosForAction(final int action) { 237 final MemberActionInfo[] infos= (MemberActionInfo[]) fTableViewer.getInput(); 238 int count= 0; 239 for (int index= 0; index < infos.length; index++) { 240 final MemberActionInfo info= infos[index]; 241 if (info.getAction() == action) 242 count++; 243 } 244 return count; 245 } 246 247 private void createButtonComposite(final Composite parent) { 248 final Composite composite= new Composite(parent, SWT.NONE); 249 composite.setLayoutData(new GridData(GridData.FILL_VERTICAL)); 250 final GridLayout layout= new GridLayout(); 251 layout.marginHeight= 0; 252 layout.marginWidth= 0; 253 composite.setLayout(layout); 254 255 fSelectAllButton= new Button(composite, SWT.PUSH); 256 fSelectAllButton.setText(RefactoringMessages.PullUpWizard_select_all_label); 257 fSelectAllButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 258 fSelectAllButton.setEnabled(true); 259 SWTUtil.setButtonDimensionHint(fSelectAllButton); 260 fSelectAllButton.addSelectionListener(new SelectionAdapter() { 261 262 public void widgetSelected(final SelectionEvent event) { 263 final IMember[] members= getMembers(); 264 setActionForMembers(members, MemberActionInfo.PUSH_DOWN_ACTION); 265 updateWizardPage(null, true); 266 } 267 }); 268 269 fDeselectAllButton= new Button(composite, SWT.PUSH); 270 fDeselectAllButton.setText(RefactoringMessages.PullUpWizard_deselect_all_label); 271 fDeselectAllButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 272 fDeselectAllButton.setEnabled(false); 273 SWTUtil.setButtonDimensionHint(fDeselectAllButton); 274 fDeselectAllButton.addSelectionListener(new SelectionAdapter() { 275 276 public void widgetSelected(final SelectionEvent event) { 277 final IMember[] members= getMembers(); 278 setActionForMembers(members, MemberActionInfo.NO_ACTION); 279 updateWizardPage(null, true); 280 } 281 }); 282 283 fEditButton= new Button(composite, SWT.PUSH); 284 fEditButton.setText(RefactoringMessages.PushDownInputPage_Edit); 285 final GridData data= new GridData(GridData.FILL_HORIZONTAL); 286 data.verticalIndent= new PixelConverter(parent).convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN); 287 fEditButton.setLayoutData(data); 288 fEditButton.setEnabled(false); 289 SWTUtil.setButtonDimensionHint(fEditButton); 290 fEditButton.addSelectionListener(new SelectionAdapter() { 291 292 public void widgetSelected(final SelectionEvent event) { 293 PushDownInputPage.this.editSelectedMembers(); 294 } 295 }); 296 297 final Button addButton= new Button(composite, SWT.PUSH); 298 addButton.setText(RefactoringMessages.PushDownInputPage_Add_Required); 299 addButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); 300 SWTUtil.setButtonDimensionHint(addButton); 301 addButton.addSelectionListener(new SelectionAdapter() { 302 303 public void widgetSelected(final SelectionEvent event) { 304 PushDownInputPage.this.markAdditionalRequiredMembersAsMembersToPushDown(); 305 } 306 }); 307 } 308 309 public void createControl(final Composite parent) { 310 final Composite composite= new Composite(parent, SWT.NONE); 311 composite.setLayout(new GridLayout()); 312 313 createMemberTableLabel(composite); 314 createMemberTableComposite(composite); 315 createStatusLine(composite); 316 317 setControl(composite); 318 Dialog.applyDialogFont(composite); 319 PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IJavaHelpContextIds.PUSH_DOWN_WIZARD_PAGE); 320 } 321 322 private void createMemberTable(final Composite parent) { 323 final TableLayoutComposite layouter= new TableLayoutComposite(parent, SWT.NONE); 324 layouter.addColumnData(new ColumnWeightData(60, true)); 325 layouter.addColumnData(new ColumnWeightData(40, true)); 326 327 final Table table= new Table(layouter, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION | SWT.CHECK); 328 table.setHeaderVisible(true); 329 table.setLinesVisible(true); 330 331 final GridData data= new GridData(GridData.FILL_BOTH); 332 data.heightHint= SWTUtil.getTableHeightHint(table, ROW_COUNT); 333 data.widthHint= convertWidthInCharsToPixels(30); 334 layouter.setLayoutData(data); 335 336 final TableLayout layout= new TableLayout(); 337 table.setLayout(layout); 338 339 final TableColumn first= new TableColumn(table, SWT.NONE); 340 first.setText(RefactoringMessages.PushDownInputPage_Member); 341 342 final TableColumn second= new TableColumn(table, SWT.NONE); 343 second.setText(RefactoringMessages.PushDownInputPage_Action); 344 345 fTableViewer= new PullPushCheckboxTableViewer(table); 346 fTableViewer.setUseHashlookup(true); 347 fTableViewer.setContentProvider(new ArrayContentProvider()); 348 fTableViewer.setLabelProvider(new MemberActionInfoLabelProvider()); 349 fTableViewer.addSelectionChangedListener(new ISelectionChangedListener() { 350 351 public void selectionChanged(final SelectionChangedEvent event) { 352 PushDownInputPage.this.updateButtonEnablementState((IStructuredSelection) event.getSelection()); 353 } 354 }); 355 fTableViewer.addCheckStateListener(new ICheckStateListener() { 356 357 public void checkStateChanged(final CheckStateChangedEvent event) { 358 final boolean checked= event.getChecked(); 359 final MemberActionInfo info= (MemberActionInfo) event.getElement(); 360 if (checked) 361 info.setAction(MemberActionInfo.PUSH_DOWN_ACTION); 362 else 363 info.setAction(MemberActionInfo.NO_ACTION); 364 updateWizardPage(null, true); 365 } 366 }); 367 fTableViewer.addDoubleClickListener(new IDoubleClickListener() { 368 369 public void doubleClick(final DoubleClickEvent event) { 370 PushDownInputPage.this.editSelectedMembers(); 371 } 372 }); 373 374 fTableViewer.setInput(getPushDownRefactoring().getPushDownProcessor().getMemberActionInfos()); 375 updateWizardPage(null, false); 376 setupCellEditors(table); 377 } 378 379 private void createMemberTableComposite(final Composite parent) { 380 final Composite composite= new Composite(parent, SWT.NONE); 381 composite.setLayoutData(new GridData(GridData.FILL_BOTH)); 382 final GridLayout layout= new GridLayout(); 383 layout.numColumns= 2; 384 layout.marginWidth= 0; 385 layout.marginHeight= 0; 386 composite.setLayout(layout); 387 388 createMemberTable(composite); 389 createButtonComposite(composite); 390 } 391 392 private void createMemberTableLabel(final Composite parent) { 393 final Label label= new Label(parent, SWT.NONE); 394 label.setText(RefactoringMessages.PushDownInputPage_Specify_actions); 395 label.setLayoutData(new GridData()); 396 } 397 398 private void createStatusLine(final Composite composite) { 399 fStatusLine= new Label(composite, SWT.NONE); 400 final GridData data= new GridData(); 401 data.horizontalSpan= 2; 402 updateStatusLine(); 403 fStatusLine.setLayoutData(data); 404 } 405 406 private Map createStringMappingForSelectedElements() { 408 final Map result= new HashMap (); 409 int action= MemberActionInfo.PUSH_DOWN_ACTION; 410 result.put(MemberActionInfoLabelProvider.getActionLabel(action), new Integer (action)); 411 int action1= MemberActionInfo.PUSH_ABSTRACT_ACTION; 412 result.put(MemberActionInfoLabelProvider.getActionLabel(action1), new Integer (action1)); 413 return result; 414 } 415 416 private void editSelectedMembers() { 417 if (!fEditButton.isEnabled()) 418 return; 419 final ISelection preserved= fTableViewer.getSelection(); 420 try { 421 final Map stringMapping= createStringMappingForSelectedElements(); 422 final String [] keys= (String []) stringMapping.keySet().toArray(new String [stringMapping.keySet().size()]); 423 Arrays.sort(keys); 424 final int initialSelectionIndex= getInitialSelectionIndexForEditDialog(stringMapping, keys); 425 426 final ComboSelectionDialog dialog= new ComboSelectionDialog(getShell(), RefactoringMessages.PushDownInputPage_Edit_members, RefactoringMessages.PushDownInputPage_Mark_selected_members, keys, initialSelectionIndex); 427 dialog.setBlockOnOpen(true); 428 if (dialog.open() == Window.CANCEL) 429 return; 430 final int action= ((Integer ) stringMapping.get(dialog.getSelectedString())).intValue(); 431 setInfoAction(getSelectedMemberActionInfos(), action); 432 } finally { 433 updateWizardPage(preserved, true); 434 } 435 } 436 437 private boolean enableEditButton(final IStructuredSelection selection) { 438 if (selection.isEmpty() || selection.size() == 0) 439 return false; 440 return selection.size() == countEditableInfos(getSelectedMemberActionInfos()); 441 } 442 443 private MemberActionInfo[] getActiveInfos() { 444 final MemberActionInfo[] infos= getPushDownRefactoring().getPushDownProcessor().getMemberActionInfos(); 445 final List result= new ArrayList (infos.length); 446 for (int index= 0; index < infos.length; index++) { 447 final MemberActionInfo info= infos[index]; 448 if (info.isActive()) 449 result.add(info); 450 } 451 return (MemberActionInfo[]) result.toArray(new MemberActionInfo[result.size()]); 452 } 453 454 private int getCommonActionCodeForSelectedInfos() { 455 final MemberActionInfo[] infos= getSelectedMemberActionInfos(); 456 if (infos.length == 0) 457 return -1; 458 459 final int code= infos[0].getAction(); 460 for (int index= 0; index < infos.length; index++) { 461 if (code != infos[index].getAction()) 462 return -1; 463 } 464 return code; 465 } 466 467 private int getInitialSelectionIndexForEditDialog(final Map mapping, final String [] keys) { 468 final int commonActionCode= getCommonActionCodeForSelectedInfos(); 469 if (commonActionCode == -1) 470 return 0; 471 for (final Iterator iterator= mapping.keySet().iterator(); iterator.hasNext();) { 472 final String key= (String ) iterator.next(); 473 final int action= ((Integer ) mapping.get(key)).intValue(); 474 if (commonActionCode == action) { 475 for (int index= 0; index < keys.length; index++) { 476 if (key.equals(keys[index])) 477 return index; 478 } 479 Assert.isTrue(false); } 481 } 482 return 0; 483 } 484 485 private IMember[] getMembers() { 486 final MemberActionInfo[] infos= (MemberActionInfo[]) fTableViewer.getInput(); 487 final List result= new ArrayList (infos.length); 488 for (int index= 0; index < infos.length; index++) { 489 result.add(infos[index].getMember()); 490 } 491 return (IMember[]) result.toArray(new IMember[result.size()]); 492 } 493 494 private PushDownRefactoring getPushDownRefactoring() { 495 return (PushDownRefactoring) getRefactoring(); 496 } 497 498 private MemberActionInfo[] getSelectedMemberActionInfos() { 499 Assert.isTrue(fTableViewer.getSelection() instanceof IStructuredSelection); 500 final List result= ((IStructuredSelection) fTableViewer.getSelection()).toList(); 501 return (MemberActionInfo[]) result.toArray(new MemberActionInfo[result.size()]); 502 } 503 504 public void markAdditionalRequiredMembersAsMembersToPushDown() { 505 try { 506 PlatformUI.getWorkbench().getActiveWorkbenchWindow().run(false, false, new IRunnableWithProgress() { 507 508 public void run(final IProgressMonitor pm) throws InvocationTargetException { 509 try { 510 getPushDownRefactoring().getPushDownProcessor().computeAdditionalRequiredMembersToPushDown(pm); 511 updateWizardPage(null, true); 512 } catch (final JavaModelException e) { 513 throw new InvocationTargetException (e); 514 } finally { 515 pm.done(); 516 } 517 } 518 }); 519 } catch (final InvocationTargetException e) { 520 ExceptionHandler.handle(e, getShell(), RefactoringMessages.PushDownInputPage_Push_Down, RefactoringMessages.PushDownInputPage_Internal_Error); 521 } catch (final InterruptedException e) { 522 Assert.isTrue(false); } 524 } 525 526 private void setActionForMembers(final IMember[] members, final int action) { 527 final MemberActionInfo[] infos= (MemberActionInfo[]) fTableViewer.getInput(); 528 for (int offset= 0; offset < members.length; offset++) { 529 for (int index= 0; index < infos.length; index++) { 530 if (infos[index].getMember().equals(members[offset])) 531 infos[index].setAction(action); 532 } 533 } 534 } 535 536 private void setupCellEditors(final Table table) { 537 final ComboBoxCellEditor comboBoxCellEditor= new ComboBoxCellEditor(); 538 comboBoxCellEditor.setStyle(SWT.READ_ONLY); 539 fTableViewer.setCellEditors(new CellEditor[] { null, comboBoxCellEditor}); 540 fTableViewer.addSelectionChangedListener(new ISelectionChangedListener() { 541 542 public void selectionChanged(final SelectionChangedEvent event) { 543 if (comboBoxCellEditor.getControl() == null & !table.isDisposed()) 544 comboBoxCellEditor.create(table); 545 Assert.isTrue(event.getSelection() instanceof IStructuredSelection); 546 final IStructuredSelection ss= (IStructuredSelection) event.getSelection(); 547 if (ss.size() != 1) 548 return; 549 final MemberActionInfo mac= (MemberActionInfo) ss.getFirstElement(); 550 comboBoxCellEditor.setItems(MemberActionInfoLabelProvider.getAvailableActionLabels(mac)); 551 comboBoxCellEditor.setValue(new Integer (mac.getAction())); 552 } 553 }); 554 555 final ICellModifier cellModifier= new PushDownCellModifier(); 556 fTableViewer.setCellModifier(cellModifier); 557 fTableViewer.setColumnProperties(new String [] { MEMBER_PROPERTY, ACTION_PROPERTY}); 558 } 559 560 public void setVisible(final boolean visible) { 561 super.setVisible(visible); 562 if (visible) { 563 fTableViewer.setSelection(new StructuredSelection(getActiveInfos()), true); 564 fTableViewer.getControl().setFocus(); 565 } 566 } 567 568 private void updateButtonEnablementState(final IStructuredSelection tableSelection) { 569 if (tableSelection == null || fEditButton == null) 570 return; 571 fEditButton.setEnabled(enableEditButton(tableSelection)); 572 if (fSelectAllButton != null) 573 fSelectAllButton.setEnabled(!areAllElementsMarkedAsPushDownAction()); 574 if (fDeselectAllButton != null) 575 fDeselectAllButton.setEnabled(!areAllElementsMarkedAsNoAction()); 576 } 577 578 private void updateStatusLine() { 579 if (fStatusLine == null) 580 return; 581 final int selected= fTableViewer.getCheckedElements().length; 582 final String [] keys= { String.valueOf(selected)}; 583 final String msg= Messages.format(RefactoringMessages.PushDownInputPage_status_line, keys); 584 fStatusLine.setText(msg); 585 } 586 587 private void updateWizardPage(final ISelection preserved, final boolean displayErrorMessage) { 588 fTableViewer.refresh(); 589 if (preserved != null) { 590 fTableViewer.getControl().setFocus(); 591 fTableViewer.setSelection(preserved); 592 } 593 checkPageCompletionStatus(displayErrorMessage); 594 updateButtonEnablementState(((IStructuredSelection) fTableViewer.getSelection())); 595 updateStatusLine(); 596 } 597 } 598 599 public PushDownWizard(final PushDownRefactoring ref) { 600 super(ref, DIALOG_BASED_USER_INTERFACE); 601 setDefaultPageTitle(RefactoringMessages.PushDownWizard_defaultPageTitle); 602 } 603 604 protected void addUserInputPages() { 605 addPage(new PushDownInputPage()); 606 } 607 } 608 | Popular Tags |