public void undelete() {
    // make a copy because the selected trash items changes as soon as trashService.undelete is called
    List<UIDeletedObject> selectedTrashFileItemsSnapshot = new ArrayList<UIDeletedObject>( selectedTrashFileItems );
    if ( selectedTrashFileItemsSnapshot != null && selectedTrashFileItemsSnapshot.size() > 0 ) {
      List<ObjectId> ids = new ArrayList<ObjectId>();
      for ( UIDeletedObject uiObj : selectedTrashFileItemsSnapshot ) {
        ids.add( uiObj.getId() );
      }
      try {
        trashService.undelete( ids );
        setTrash( trashService.getTrash() );
        for ( UIDeletedObject uiObj : selectedTrashFileItemsSnapshot ) {
          // find the closest UIRepositoryDirectory that is in the dirMap
          RepositoryDirectoryInterface dir = repository.findDirectory( uiObj.getOriginalParentPath() );
          while ( dir != null && dirMap.get( dir.getObjectId() ) == null ) {
            dir = dir.getParent();
          }
          // now refresh that UIRepositoryDirectory so that the file/folders deck instantly refreshes on undelete
          if ( dir != null ) {
            dirMap.get( dir.getObjectId() ).refresh();
          }
          // if transformation or directory with transformations call extension to restore data services references.
          if ( RepositoryObjectType.TRANSFORMATION.name().equals( uiObj.getType() ) ) {
            TransMeta transMeta = repository.loadTransformation( uiObj.getId(), null );
            ExtensionPointHandler
                .callExtensionPoint( LogChannel.GENERAL, KettleExtensionPoint.TransAfterOpen.id, transMeta );
            transMeta.clearChanged();
          } else if ( !RepositoryObjectType.JOB.name().equals( uiObj.getType() ) ) {
            // if not a transformation and not a job then is a Directory
            RepositoryDirectoryInterface
                actualDir =
                repository.findDirectory(
                    uiObj.getOriginalParentPath() + RepositoryDirectory.DIRECTORY_SEPARATOR + uiObj.getName() );
            if ( actualDir != null ) {
              List<RepositoryElementMetaInterface> transformations = new ArrayList<>();
              getAllTransformations( actualDir, transformations );
              for ( RepositoryElementMetaInterface repositoryElementMetaInterface : transformations ) {
                TransMeta transMeta = repository.loadTransformation( repositoryElementMetaInterface.getObjectId(), null );
                ExtensionPointHandler
                    .callExtensionPoint( LogChannel.GENERAL, KettleExtensionPoint.TransAfterOpen.id, transMeta );
                transMeta.clearChanged();
              }
            } else {
              displayExceptionMessage( BaseMessages.getString( PKG, "TrashBrowseController.UnableToRestoreDirectory",
                  uiObj.getOriginalParentPath() + RepositoryDirectory.DIRECTORY_SEPARATOR + uiObj.getName() ) );
            }
          }
        }
        deck.setSelectedIndex( 1 );
      } catch ( Throwable th ) {
        if ( mainController == null || !mainController.handleLostRepository( th ) ) {
          displayExceptionMessage( BaseMessages.getString( PKG,
              "TrashBrowseController.UnableToRestoreFile", th.getLocalizedMessage() ) ); //$NON-NLS-1$
        }
      }
    } else {
      // ui probably allowed the button to be enabled when it shouldn't have been enabled
      throw new RuntimeException();
    }
  }
@Test
  public void testExceptionNotHandle() throws Exception {
    RuntimeException runtimeException = new RuntimeException( "Exception handle" );
    when( selectedTrashFileItemsMock.toArray() )
        .thenReturn( new TrashBrowseController.UIDeletedObject[] { uiDirectoryObjectMock } );
    doThrow( runtimeException ).when( trashServiceMock ).undelete( anyList() );
    doReturn( true ).when( mainControllerMock ).handleLostRepository( any( Throwable.class ) );

    trBrController.undelete();

    verify( messageBoxMock, never() ).setTitle( "Error" );
    verify( messageBoxMock, never() ).setAcceptLabel( "OK" );
    verify( messageBoxMock, never() ).setMessage( contains( "Exception handle" ) );
    verify( messageBoxMock, never() ).open();
    verify( deckMock, never() ).setSelectedIndex( 1 );
  }