Changeset 3899


Ignore:
Timestamp:
Oct 20, 2010, 1:10:39 PM (13 years ago)
Author:
Gregory Vincic
Message:

Fixes #712.

Location:
trunk/client/servlet/src/org/proteios/action
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/client/servlet/src/org/proteios/action/directory/ViewActiveDirectory.java

    r3888 r3899  
    11/*
    2  $Id$
    3 
    4  Copyright (C) 2006 Gregory Vincic
    5  Copyright (C) 2007 Gregory Vincic, Olle Mansson
    6 
    7  Files are copyright by their respective authors. The contributions to
    8  files where copyright is not explicitly stated can be traced with the
    9  source code revision system.
    10 
    11  This file is part of Proteios.
    12  Available at http://www.proteios.org/
    13 
    14  Proteios-2.x is free software; you can redistribute it and/or
    15  modify it under the terms of the GNU General Public License
    16  as published by the Free Software Foundation; either version 2
    17  of the License, or (at your option) any later version.
    18 
    19  Proteios is distributed in the hope that it will be useful,
    20  but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    22  GNU General Public License for more details.
    23 
    24  You should have received a copy of the GNU General Public License
    25  along with this program; if not, write to the Free Software
    26  Foundation, Inc., 59 Temple Place - Suite 330,
    27  Boston, MA  02111-1307, USA.
    28  */
     2    $Id$
     3   
     4    Copyright (C) 2006 Gregory Vincic
     5    Copyright (C) 2007 Gregory Vincic, Olle Mansson
     6   
     7    Files are copyright by their respective authors. The contributions to
     8    files where copyright is not explicitly stated can be traced with the
     9    source code revision system.
     10   
     11    This file is part of Proteios.
     12    Available at http://www.proteios.org/
     13   
     14    Proteios-2.x is free software; you can redistribute it and/or
     15    modify it under the terms of the GNU General Public License
     16    as published by the Free Software Foundation; either version 2
     17    of the License, or (at your option) any later version.
     18   
     19    Proteios is distributed in the hope that it will be useful,
     20    but WITHOUT ANY WARRANTY; without even the implied warranty of
     21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     22    GNU General Public License for more details.
     23   
     24    You should have received a copy of the GNU General Public License
     25    along with this program; if not, write to the Free Software
     26    Foundation, Inc., 59 Temple Place - Suite 330,
     27    Boston, MA  02111-1307, USA.
     28*/
    2929package org.proteios.action.directory;
    3030
     
    8585
    8686/**
    87  * Displays properties of a Directory and the content of that directory.
    88  *
    89  * @author gregory
    90  */
     87    * Displays properties of a Directory and the content of that directory.
     88    *
     89    * @author gregory
     90*/
    9191public class ViewActiveDirectory
    92     extends ProteiosAction<ViewActiveDirectory>
     92extends ProteiosAction<ViewActiveDirectory>
    9393{
    94   /**
    95    * Session identifier for an active directory
    96    */
    97   public static final VInteger VDIRID = new VInteger("active.dir.id", 1, true);
    98   public static final VBoolean VSELECT = new VBoolean("select", true);
    99   public static final VBoolean VSELECTMOVEDIR = new VBoolean(
    100     "select.move.dir", false);
    101   public static final VBoolean VMOVEFILESSTART = new VBoolean("moveFilesStart", false);
    102   public static final VBoolean VMOVEFILES = new VBoolean("moveFiles", false);
    103   public static final VBoolean VTABLEUPDATEBUTTONCLICKED = new VBoolean("tableUpdateButtonClicked", false);
    104 
    105 
    106   /**
    107    * Creates a layout for viewing/selecting the contents of a directory. The
    108    * details of what the layout contains depends on Boolean flags transferred
    109    * as valid parameters, that indicate the purpose of the directory listing.
    110    * The general layout consists of a directory table and a file table. The
    111    * directory table has two tabs, a 'contents' tab and a 'properties' tab.
    112    * The directory 'contents' tab shows a list of sub-directories in the
    113    * current directory, as well as a link to the parent directory. The file
    114    * table shows a list of files in the current directory. The file table may
    115    * be configured by the user via a popup window, and also has a filter row
    116    * below the table header.
    117    */
    118   @Override
    119   protected void runMe()
    120       throws ActionException, InvalidParameterValue
    121   {
    122     log.debug("Start");
    123     // Define
    124     Boolean select, selectMoveDir, moveFilesStart, moveFilesMode = null;
    125     String actionId;
    126     DbControl dc;
    127     Integer itemId, start, max;
    128     ItemQuery<File> query;
    129     Directory rootDir;
    130     User user;
    131     ItemFactory factory;
    132     List<String> columnOrder;
    133     Project activeP;
    134     QueryFactory qf;
    135     //
    136     // Fetch table update button clicked flag
    137     boolean tableUpdateButtonClicked = fetchTableUpdateButtonClickedFlag();
    138     log.debug("tableUpdateButtonClicked = " + tableUpdateButtonClicked);
    139     // Create
    140     // Check if user has selected file[s] in directory table to move
    141     moveFilesStart = getValidBoolean(VMOVEFILESSTART);
    142     if (moveFilesStart == null)
    143     {
    144       moveFilesStart = false;
    145       log
    146         .debug("Input moveFilesStart == null, reset to moveFilesStart = " + moveFilesStart);
    147     }
    148     log.debug("moveFilesStart = " + moveFilesStart);
    149     if (moveFilesStart)
    150     {
    151       // Check input
    152       List<Integer> tmpFileIds = getValidIntegerList(ItemIdField.VPARAM);
    153       log.debug("tmpFileIds from ItemIdField.VPARAM for input check = " + tmpFileIds);
    154       if (tmpFileIds != null && tmpFileIds.size() > 0)
    155       {
    156         setSessionAttribute(VSELECT, true);
    157         setSessionAttribute(VSELECTMOVEDIR, true);
    158         setSessionAttribute(VMOVEFILES, true);
    159         setSessionAttribute(ForwardField.VPARAM, MoveFiles.class.getName());
    160       }
    161       else
    162       {
    163         setError("Select at least one file to move");
    164       }
    165     }
    166     select = getSessionAttribute(VSELECT);
    167     actionId = getSessionAttribute(ForwardField.VPARAM);
    168     selectMoveDir = getSessionAttribute(VSELECTMOVEDIR);
    169     moveFilesMode = getSessionAttribute(VMOVEFILES);
    170     qf = getQueryFactory();
    171     dc = newDbControl();
    172     activeP = getActiveProject(dc);
    173     // Use
    174     if (selectMoveDir == null)
    175     {
    176       selectMoveDir = false;
    177       log
    178         .debug("Input selectMoveDir == null, reset to selectMoveDir = " + selectMoveDir);
    179     }
    180     if (moveFilesMode == null)
    181     {
    182       moveFilesMode = false;
    183       log
    184         .debug("Input moveFilesMode == null, reset to moveFilesMode = " + moveFilesMode);
    185     }
    186     log.debug("select = " + select + " selectMoveDir = " + selectMoveDir + " moveFilesMode = " + moveFilesMode);
    187     /***********************************************************************
    188      * Create file table
    189      */
    190     // A user clicked a directory
    191     itemId = getSessionAttribute(ViewActiveDirectory.VDIRID);
    192     if (itemId == null)
    193     {
    194       // No directory selected, first time
    195       user = getOwner();
    196       dc.reattachItem(user);
    197       rootDir = user.getHomeDirectory();
    198     }
    199     else
    200     {
    201       factory = getItemFactory(dc);
    202       rootDir = factory.getById(Directory.class, itemId);
    203     }
    204     // Query with parameters
    205     query = rootDir.getFileQuery();
    206     start = 0;
    207     max = 1000000000;
    208     columnOrder = getValidStringList(ConfigureTableFactory2.VCOLUMNORDER);
    209     // Use
    210     setAttribute(ConfigureTableFactory2.VDATACLASS, FileData.class
    211       .getName());
    212     setAttribute(ConfigureTableFactory2.VWRAPPERCLASS, File.class.getName());
    213     // Configure TableFactory2
    214     ConfigureTableFactory2 confTF2 = new ConfigureTableFactory2(getOwner());
    215     confTF2.setExternalTableUpdateButtonClicked(tableUpdateButtonClicked);
    216     TableFactory2 tableFactory2 = confTF2.configure(dc, File.class,
    217       FileData.class, query, start, max, columnOrder, this, this
    218         .getTableFactory2());
    219     // Create file table
    220     Table fileTable = tableFactory2.build();
    221   // Add asPopup parameter to hide the menu in the next step. This is needed when the action is used
    222   // in the wizard
    223   if (getActionFactory().getAsPopup())
    224     {
    225       TextField<Boolean> asPopup = new TextField<Boolean>(
    226         ActionFactory.VPOPUP);
    227       asPopup.setHidden(true);
    228       asPopup.setValue(true);
    229       fileTable.add(asPopup);
    230     }
    231 
    232     /**
    233      * If in the top level of the project, add all files visible to the
    234      * project, but which are not in an accessible directory
    235      */
    236     if (activeP != null && activeP.getProjectDirectory() != null && activeP.getProjectDirectory().equals(rootDir))
    237     {
    238       log.debug("Checking for exclude directories");
    239       query = qf.select(File.class);
    240       query.exclude(Include.MINE);
    241       query.include(Include.IN_PROJECT);
    242       ItemQuery<Directory> dirQuery = qf.select(Directory.class);
    243       dirQuery.exclude(Include.MINE);
    244       dirQuery.include(Include.IN_PROJECT);
    245       List<Directory> allDirs = dirQuery.list(dc);
    246       // Specifically add the current dir so that files are not repeated
    247       query.restrictPermanent(Restrictions.neq(Hql.property("directory"),
    248         Hql.entity(rootDir)));
    249       for (Directory currentDir : allDirs)
    250       {
    251         log.debug("Excluded dir: " + currentDir.getName());
    252         query.restrictPermanent(Restrictions.neq(Hql
    253           .property("directory"), Hql.entity(currentDir)));
    254       }
    255       tableFactory2 = confTF2.configure(dc, File.class, FileData.class,
    256         query, start, max, columnOrder, this, this.getTableFactory2());
    257       Table newTable = tableFactory2.build();
    258       for (Row r : newTable.getRows())
    259       {       
    260         r.getTags().add("shared");
    261         fileTable.addRow(r);
    262       }
    263     }
    264     fileTable.setTitle("Files");
    265     // Only add file view action if no dedicated file selection
    266     if (select == null || select)
    267     {
    268       /*
    269        * Column actions are transferred to cells in rows, when the table
    270        * is built.
    271        */
    272       for (Row row : fileTable.getRows())
    273       {
    274         for (Cell<?> cell : row.getCells())
    275         {
    276           cell.setActionLink(null);
    277         }
    278       }
    279     }
    280     //
    281     fileTable.add(new TextField<String>(ConfigureTableFactory2.VWRAPPERCLASS, File.class.getName()));
    282     fileTable.add(new TextField<String>(ConfigureTableFactory2.VDATACLASS, FileData.class.getName()));
    283     // Add query parameters
    284     fileTable.add(new TextField<Integer>(ConfigureTableFactory2.VQUERYSTARTAT, start));
    285     // Set forward action
    286     fileTable.add(new TextField<String>(ConfigureTableFactory2.VFORWARDTO, ViewActiveDirectory.class.getName()));
    287     // Set this action as the table configuration action
    288     fileTable.setConfigureTableAction(getActionFactory().getActionLink(
    289       ConfigureTableFactory2.class, ""));
    290     // We do not use the scroller when browsing for files
    291     fileTable.setScroller(null);
    292     // Add column order
    293     List<Column> header = fileTable.getHeader();
    294     for (int i = 0; i < header.size(); i++)
    295     {
    296       AttributeDefinition ad = header.get(i).getAttributeDefinition();
    297       fileTable.add(new TextField<String>(ConfigureTableFactory2.VCOLUMNORDER, ad.getKey()));
    298     }
    299     // Add class name needed for delete action
    300     fileTable.add(new TextField<String>(FormFactory.VCLASSNAME, File.class.getName()));
    301     // Add optional form title
    302     String formTitle = fetchFormTitle(select, selectMoveDir);
    303     fileTable.add(new TitleField(formTitle));
    304     // Add optional special name for "Next" button
    305     String nextButtonName = fetchNextButtonName(select, selectMoveDir);
    306     fileTable.add(new NextButtonNameField(nextButtonName));
    307     // Use getRequest().getAttribute("table") in a
    308     // subsequent action to get the created table.
    309     //
    310     // Add update button
    311     Toolbar fileToolbar = new Toolbar();
    312     fileTable.setToolbar(fileToolbar);
    313     ActionLink update = getActionFactory().getActionLink(
    314       ViewActiveDirectory.class, "Update");
    315     update.addParameter(VTABLEUPDATEBUTTONCLICKED, true);
    316     fileToolbar.add(update);
    317     //
    318     String path = rootDir.getPath().toString();
    319     fileTable.setTitle(fileTable.getTitle());
    320     //
    321     ClassDescriptor wrapperDescriptor = new ClassDescriptor(File.class);
    322     setAttribute("table", fileTable);
    323     setAttribute("tableQuery", query);
    324     setAttribute("header", header);
    325     setAttribute("wrapperDescriptor", wrapperDescriptor);
    326     /*
    327      * Directory table
    328      */
    329     // prependDirectories(fileTable, rootDir, select, selectMoveDir);
    330     Table dirTable = createDirectoryTable(fileTable, rootDir, select,
    331       selectMoveDir, moveFilesMode, moveFilesStart);
    332     Toolbar dirToolbar = new Toolbar();
    333     dirTable.setToolbar(dirToolbar);
    334     dirTable.add(new TextField<String>(ConfigureTableFactory2.VWRAPPERCLASS, Directory.class.getName()));
    335     // We do not use the scroller when browsing for directories
    336     dirTable.setScroller(null);
    337     //
    338     TabSet ts = null;
    339     Title title = null;
    340     /***********************************************************************
    341      * Directory content form
    342      */
    343     if (select == null || select)
    344     {
    345       // Get optional special title for file selection form
    346       formTitle = fetchFormTitle(select, selectMoveDir);
    347       // Get optional special name for "Next" button
    348       nextButtonName = fetchNextButtonName(select, selectMoveDir);
    349       /*
    350        * If selection is for directory to move file to, override above.
    351        */
    352       if (selectMoveDir)
    353       {
    354         // Add button to directory table tool bar
    355         // Remove default buttons
    356         dirToolbar.list().clear();
    357         // dirToolbar.clear();
    358         // Add a possibly renamed "Next" button
    359         ActionLink al = new ActionLink(nextButtonName, actionId);
    360         dirToolbar.setDefaultAction(al);
    361         dirToolbar.add(al);
    362         /*
    363          * Moving several files
    364          */
    365         log.debug("moveFilesMode = " + moveFilesMode);
    366         if (moveFilesMode)
    367         {
    368           /*
    369            * This action may be called several times when
    370            * navigating from the source to the target directory.
    371            * First time the id values for selected files are
    372            * stored in the default valid parameter VInteger ItemIdField.VPARAM,
    373            * otherwise they are stored in valid parameter VInteger ViewActiveFile.VFILEID.
    374            */
    375           List<Integer> tmpFileIds = null;
    376           // Check if first time when navigating to target directory
    377           if (moveFilesStart)
    378           {
    379             tmpFileIds = getValidIntegerList(ItemIdField.VPARAM);
    380             log.debug("tmpFileIds from ItemIdField.VPARAM = " + tmpFileIds);
    381           }
    382           else
    383           {
    384             tmpFileIds = getValidIntegerList(ViewActiveFile.VFILEID);
    385             log.debug("tmpFileIds from ViewActiveFile.VFILEID = " + tmpFileIds);
    386           }
    387           log.debug("tmpFileIds = " + tmpFileIds);
    388           // Add id values for selected files as parameters to action link
    389           if (tmpFileIds != null && tmpFileIds.size() > 0)
    390           {
    391             // Set id values for source files
    392             for (Integer fileId : tmpFileIds)
    393             {
    394           getFormFactory().addHiddenField(dirTable, ViewActiveFile.VFILEID, fileId);
    395             }
    396           }
    397         }
    398       }
    399       title = new Title(formTitle);
    400       // Add button to file table tool bar
    401       // Remove default buttons
    402       fileToolbar.list().clear();
    403       fileToolbar.clear();
    404       // Add update button
    405       fileToolbar.add(update);
    406       // Add a possibly renamed "Next" button
    407       ActionLink al = new ActionLink(nextButtonName, actionId);
    408       // fileToolbar.setDefaultAction(al);
    409       fileToolbar.setDefaultAction(update);
    410       fileToolbar.add(al);
    411       log.debug("(2) fileToolbar.getDefaultAction() = " + fileToolbar
    412         .getDefaultAction());
    413     }
    414     else
    415     {
    416         title = new Title("Files");
    417       // Simple browsing of the directory
    418       // Button for new directory
    419       ActionLink newDirectoryBtn = getActionFactory().getActionLink(
    420         NewDirectory.class, "NewDirectory");
    421       dirToolbar.add(newDirectoryBtn);
    422       // Button for deleting directory
    423       ActionLink deleteDirectoryBtn = getActionFactory().getActionLink(
    424         DeleteDirectory.class, "DeleteDirectory");
    425       dirToolbar.add(deleteDirectoryBtn);
    426       // Add directory tool bar
    427       dirTable.setToolbar(dirToolbar);
    428       // Simple browsing of the directory
    429       // Button for moving file[s]
    430       ActionLink moveAction = getActionFactory().getActionLink(
    431         ViewActiveDirectory.class, "Move");
    432       moveAction.addParameter(VMOVEFILESSTART, true);
    433       fileToolbar.add(moveAction);
    434       if (fileTable.getRows().size() == 0)
    435       {
    436         moveAction.disable();
    437       }
    438       // Button for deleting file
    439       ActionLink deleteAction = getActionFactory().getActionLink(
    440         DeleteItems.class, "Delete");
    441       fileToolbar.add(deleteAction);
    442       if (fileTable.getRows().size() == 0)
    443       {
    444         deleteAction.disable();
    445       }
    446       // Button for sharing directory
    447       PopupLink shareAction = new PopupLink();
    448       GUIElement<?> popupContent = ShareToProject.createPermissionForm(true);
    449       shareAction.setContent(popupContent);
    450       shareAction.setLabel("UseInProject");
    451       // Button for sharing file
    452       PopupLink shareFileAction = new PopupLink();
    453       GUIElement<?> popupContent2 = ShareToProject.createPermissionForm(false);
    454       shareFileAction.setContent(popupContent2);
    455       shareFileAction.setLabel("UseInProject");
    456            
    457       if (dc.getSessionControl().getActiveProjectId() == 0)
    458       {
    459         shareAction.disable();
    460         shareFileAction.disable();
    461       }
    462       dirToolbar.add(shareAction);
    463       fileToolbar.add(shareFileAction);
    464       // Button for uploading file
    465       ActionLink upload = getActionFactory().getActionLink(NewFile.class,
    466         "UploadFile");
    467       fileToolbar.add(upload);
    468       // Button for uploading demo files
    469       fileToolbar.add(getActionFactory().getActionLink(
    470         UploadDemoFiles.class, "UploadDemoFiles"));
    471       log.debug("(3) fileToolbar.getDefaultAction() = " + fileToolbar
    472         .getDefaultAction());
    473       /*******************************************************************
    474        * Directory content container
    475        */
    476       RowContainer contentContainer = new RowContainer();
    477       contentContainer.add(dirTable);
    478       contentContainer.add(fileTable);
    479       /*******************************************************************
    480        * Directory properties form
    481        */
    482       Form propertiesForm = getFormFactory().getForm(Directory.class,
    483         rootDir);
    484       // Toolbar
    485       Toolbar dirToolbar2 = new Toolbar();
    486       dirToolbar2.add(getActionFactory().getActionLink(
    487         SaveDirectory.class, "Save"));
    488       propertiesForm.setToolbar(dirToolbar2);
    489       /*******************************************************************
    490        * Directory extensions
    491        */
    492       @SuppressWarnings("unused")
    493       List<DirectoryContext> directoryContexts = getRegistry()
    494         .getContexts(DirectoryContext.class);
    495       if (directoryContexts == null)
    496       {
    497         log.debug("directoryContexts = null");
    498       }
    499       else
    500       {
    501         log.debug("directoryContexts.size() = " + directoryContexts
    502           .size());
    503       }
    504       if (!directoryContexts.isEmpty())
    505       {
    506         Table dirExtTable = new Table("dirExtensionsTable");
    507         List<Column> dirExtHeader = new ArrayList<Column>(2);
    508         Column<String> name = new Column<String>("Name");
    509         dirExtHeader.add(name);
    510         Column<String> description = new Column<String>("Description");
    511         dirExtHeader.add(description);
    512         dirExtTable.setHeader(dirExtHeader);
    513         int rowId = 0;
    514         for (DirectoryContext context : directoryContexts)
    515         {
    516           rowId++;
    517           Row row = new Row(rowId);
    518           // Name column
    519           log.debug("context.getLabel() = \"" + context.getLabel() + "\"");
    520           Cell<String> nameCell = new Cell<String>(context.getLabel());
    521           AbstractLink link = context
    522             .getActionLink(getActionFactory());
    523           // Link the extensions so that when one is selected the
    524           // files table/form is posted to the given action.
    525           CrossLink postTableLink = new CrossLink(dirTable, link);
    526           nameCell.setActionLink(postTableLink);
    527           row.addCell(nameCell);
    528           // Description column
    529           log.debug("context.getDescription() = \"" + context.getDescription() + "\"");
    530           Cell<String> descCell = new Cell<String>(context.getDescription());
    531           descCell.setActionLink(postTableLink);
    532           row.addCell(descCell);
    533           //
    534           dirExtTable.addRow(row);
    535         }
    536         PopupLink dirExtensions = new PopupLink();
    537         TitledWindow popup = new TitledWindow(
    538           "ExtensionsForDirectories");
    539         popup.setStatic(false);
    540         popup.setContent(dirExtTable);
    541         dirExtensions.setLabel("ExtensionsForDirectories");
    542         dirExtensions.setContent(popup);
    543         dirToolbar.add(dirExtensions);
    544       }
    545       /*******************************************************************
    546        * File extensions
    547        */
    548       @SuppressWarnings("unused")
    549       List<FileContext> fileContexts = getRegistry().getContexts(
    550         FileContext.class);
    551       if (fileContexts == null)
    552       {
    553         log.debug("fileContexts = null");
    554       }
    555       else
    556       {
    557         log.debug("fileContexts.size() = " + fileContexts.size());
    558       }
    559       if (!fileContexts.isEmpty())
    560       {
    561         Table fileExtTable = new Table("fileExtensionsTable");
    562         List<Column> fileExtHeader = new ArrayList<Column>(2);
    563         Column<String> name = new Column<String>("Name");
    564         fileExtHeader.add(name);
    565         Column<String> description = new Column<String>("Description");
    566         fileExtHeader.add(description);
    567         fileExtTable.setHeader(fileExtHeader);
    568         int rowId = 0;
    569         for (FileContext context : fileContexts)
    570         {
    571           rowId++;
    572           Row row = new Row(rowId);
    573           // Name column
    574           log.debug("context.getLabel() = \"" + context.getLabel() + "\"");
    575           Cell<String> nameCell = new Cell<String>(context.getLabel());
    576           AbstractLink link = context
    577             .getActionLink(getActionFactory());
    578           // Link the extensions so that when one is selected the
    579           // files table/form is posted to the given action.
    580           CrossLink postTableLink = new CrossLink(fileTable, link);
    581           nameCell.setActionLink(postTableLink);
    582           row.addCell(nameCell);
    583           // Description column
    584           log.debug("context.getDescription() = \"" + context.getDescription() + "\"");
    585           Cell<String> descCell = new Cell<String>(context.getDescription());
    586           descCell.setActionLink(postTableLink);
    587           row.addCell(descCell);
    588           //
    589           fileExtTable.addRow(row);
    590         }
    591         TitledWindow popup = new TitledWindow("ExtensionsForFiles");
    592         popup.setStatic(false);
    593         popup.setContent(fileExtTable);
    594         PopupLink fileExtensions = new PopupLink();
    595         fileExtensions.setLabel("ExtensionsForFiles");
    596         fileExtensions.setContent(popup);
    597         fileToolbar.add(fileExtensions);
    598       }
    599       /*******************************************************************
    600        * Tab set
    601        */
    602       ts = new TabSet();
    603       // Content tab
    604       Tab contentTab = new Tab("Content", "dirContent");
    605       contentTab.setGuiElement(contentContainer);
    606       contentTab.setSelected(true);
    607       ts.add(contentTab);
    608       // Properties tab
    609       Tab propertiesTab = new Tab("Properties", "dirProperties");
    610       propertiesTab.setGuiElement(propertiesForm);
    611       ts.add(propertiesTab);
    612     }
    613     /***********************************************************************
    614      * Layout
    615      */
    616     RowLayout layout = getLayoutFactory().getRowLayout();
    617     layout.add(title);
    618     // Directory tab set
    619     if (ts != null)
    620     {
    621       layout.add(ts);
    622     }
    623     else
    624     {
    625       if (selectMoveDir)
    626       {
    627         layout.add(dirTable);
    628       }
    629       else
    630       {
    631         layout.add(dirTable);
    632         // Add file table
    633         layout.add(fileTable);
    634       }
    635     }
    636     //
    637     setLayout(layout);
    638   }
    639 
    640 
    641   /**
    642    * Obtains title for file/directory selection form from valid parameter.
    643    *
    644    * @param select Boolean Indicates file selection
    645    * @param selectMoveDir Boolean Indicates directory selection
    646    * @return String Title for file selection form
    647    */
    648   @SuppressWarnings("unchecked")
    649   private String fetchFormTitle(Boolean select, Boolean selectMoveDir)
    650   {
    651     String formTitle = null;
    652     if (select == null || select)
    653     {
    654       // Get optional special title for file selection form
    655       try
    656       {
    657         formTitle = getString(TitleField.VPARAM);
    658       }
    659       catch (InvalidParameterValue e)
    660       {}
    661       if (formTitle == null || formTitle.equals(""))
    662       {
    663         formTitle = getSessionAttribute(TitleField.VPARAM);
    664       }
    665       if (formTitle == null || formTitle.equals(""))
    666       {
    667         formTitle = new String("Select file[s]");
    668       }
    669       // If selection is for directory to move file to, override above
    670       if (selectMoveDir)
    671       {
    672         formTitle = new String("Move to target directory");
    673       }
    674     }
    675     return formTitle;
    676   }
    677 
    678 
    679   /**
    680    * Obtains name for for "Next" button in file/directory selection form from
    681    * valid parameter.
    682    *
    683    * @param select Boolean Indicates file selection
    684    * @param selectMoveDir Boolean Indicates directory selection
    685    * @return String Name for "Next" button in file selection form
    686    */
    687   @SuppressWarnings("unchecked")
    688   private String fetchNextButtonName(Boolean select, Boolean selectMoveDir)
    689   {
    690     String nextButtonName = null;
    691     if (select == null || select)
    692     {
    693       // Get optional special name for "Next" button
    694       try
    695       {
    696         nextButtonName = getString(NextButtonNameField.VPARAM);
    697       }
    698       catch (InvalidParameterValue e)
    699       {}
    700       if (nextButtonName == null || nextButtonName.equals(""))
    701       {
    702         nextButtonName = getSessionAttribute(NextButtonNameField.VPARAM);
    703       }
    704       if (nextButtonName == null || nextButtonName.equals(""))
    705       {
    706         nextButtonName = new String("Next");
    707       }
    708       // If selection is for directory to move file to, override above
    709       if (selectMoveDir)
    710       {
    711         nextButtonName = new String("Next");
    712       }
    713     }
    714     return nextButtonName;
    715   }
    716 
    717 
    718   /**
    719    * Creates a directory table showing sub-directories in current directory,
    720    * as well as a link to parent directory. The table columns are defined by
    721    * the template table.
    722    *
    723    * @param templateTable Table Template table for selecting columns.
    724    * @param dir Directory Source directory.
    725    * @param select Boolean Flag indicating file selection mode.
    726    * @param selectMoveDir Boolean Flag indicating directory selection mode
    727    *        (overrides file selection mode).
    728    * @param moveFilesMode Boolean Flag indicating file batch move mode.
    729    * @param moveFilesStart Boolean Flag indicating file batch move start.
    730    * @return Table
    731    */
    732   @SuppressWarnings("unchecked")
    733   private Table createDirectoryTable(Table templateTable, Directory dir,
    734       Boolean select, Boolean selectMoveDir, Boolean moveFilesMode, Boolean moveFilesStart)
    735   {
    736     // Define
    737     ItemQuery<Directory> query;
    738     TableFactory tfactory;
    739     DbControl dc;
    740     Project activeP;
    741     QueryFactory qf;
    742   String path = dir.getPath().toString();
    743     // Create
    744     qf = getQueryFactory();
    745     dc = newDbControl();
    746     activeP = getActiveProject(dc);
    747     tfactory = getTableFactory();
    748     tfactory.setDbControl(dc);
    749     query = dir.getSubDirectories();
    750     if (activeP != null)
    751     {
    752       query.include(Include.IN_PROJECT);
    753     }
    754     tfactory.reset();
    755     tfactory.setDbControl(dir.getDbControl());
    756     tfactory.setItemClass(Directory.class);
    757     tfactory.setQuery(query);
    758     // Allow unlimited number of rows in table
    759     tfactory.setMaxResults(0);
    760     ActionLink clickAction = null;
    761     if (select == null || select)
    762     {
    763       // Get optional special title for file selection form
    764       String formTitle = fetchFormTitle(select, selectMoveDir);
    765       // Get optional special name for "Next" button
    766       String nextButtonName = fetchNextButtonName(select, selectMoveDir);
    767       clickAction = getActionFactory().getActionLink(SelectFile.class,
    768         "View");
    769       clickAction
    770         .addParameter(TitleField.VPARAM, formTitle);
    771       clickAction.addParameter(NextButtonNameField.VPARAM,
    772         nextButtonName);
    773       if (moveFilesMode)
    774       {
    775         /*
    776          * This action may be called several times when
    777          * navigating from the source to the target directory.
    778          * First time the id values for selected files are
    779          * stored in the default valid parameter VInteger ItemIdField.VPARAM,
    780          * otherwise they are stored in valid parameter VInteger ViewActiveFile.VFILEID.
    781          */
    782         List<Integer> tmpFileIds = null;
    783         // Check if first time when navigating to target directory
    784         if (moveFilesStart)
    785         {
    786           try
    787           {
    788             tmpFileIds = getValidIntegerList(ItemIdField.VPARAM);
    789           }
    790           catch (Exception e)
    791           {
    792             log.debug("Exception when trying to retrieve file id list from ItemIdField.VPARAM: " + e);
    793           }
    794           log.debug("tmpFileIds from ItemIdField.VPARAM = " + tmpFileIds);
    795         }
    796         else
    797         {
    798           try
    799           {
    800             tmpFileIds = getValidIntegerList(ViewActiveFile.VFILEID);
    801           }
    802           catch (Exception e)
    803           {
    804             log.debug("Exception when trying to retrieve file id list from ViewActiveFile.VFILEID: " + e);
    805           }
    806           log.debug("tmpFileIds from ViewActiveFile.VFILEID = " + tmpFileIds);
    807         }
    808         log.debug("tmpFileIds = " + tmpFileIds);
    809         // Add id values for selected files as parameters to click action
    810         if (tmpFileIds != null && tmpFileIds.size() > 0)
    811         {
    812           // Set id values for source files
    813           for (Integer fileId : tmpFileIds)
    814           {
    815             clickAction.addParameter(ViewActiveFile.VFILEID, fileId);
    816           }
    817         }
    818       }
    819     }
    820     else
    821     {
    822       clickAction = getActionFactory().getActionLink(ViewDirectory.class,
    823         "View");
    824     }
    825     tfactory.setColumnAction("Name", clickAction);
    826     Table tmpTable = tfactory.build();
    827     /**
    828      * If in the top level of the project, also show directories that are
    829      * shared to the project, but originate in other projects
    830      */
    831     if (activeP != null && activeP.getProjectDirectory().equals(dir))
    832     {
    833       dir.getProjectKey();
    834       query = qf.select(Directory.class);
    835       query.exclude(Include.MINE);
    836       query.include(Include.IN_PROJECT);
    837       List<Directory> allDirs = query.list(dc);
    838       List<Integer> excludeDirs = new ArrayList<Integer>();
    839       boolean use = false;
    840       // Only list the top directories, do not include the current dir or
    841       // directories with it as parent
    842       for (Directory currentDir : allDirs)
    843       {
    844         if (!allDirs.contains(currentDir.getParent()) && !currentDir
    845           .equals(dir) && !currentDir.getParent().equals(dir))
    846         {
    847           log.debug("Included dir: " + currentDir.getName());
    848           use = true;
    849         }
    850         else
    851         {
    852           excludeDirs.add(currentDir.getId());
    853           log.debug("Excluded dir: " + currentDir.getName());
    854         }
    855       }
    856       query.reset();
    857       // Add directories if there are any
    858       if (use)
    859       {
    860         for (Integer id : excludeDirs)
    861         {
    862           query.restrict(Restrictions.neq(Hql.property("id"),
    863             Expressions.integer(id.intValue())));
    864         }
    865         tfactory.setQuery(query);
    866         Table tabletop = tfactory.build();
    867         for (Row r : tabletop.getRows())
    868         {
    869           r.getTags().add("shared");         
    870         }
    871         // Merge the tables
    872         for (Row r : tmpTable.getRows())
    873         {
    874           tabletop.addRow(r);
    875         }
    876         tmpTable = tabletop;
    877       }
    878     }
    879     // Create adapted directory table
    880     Table table = new Table("DirectoryTable");
    881     // Set title explicitly, to get correct plural for "Directory"
    882     table.setTitle("Directory");
    883     table.setSubtitle(path);
    884     // Adapt header to template table
    885     /*
    886      * Simply using the template header,
    887      * table.setHeader(templateTable.getHeader()); would work if the latter
    888      * did not include an appended filter row.
    889      */
    890     List<Column> adaptedHeader = adaptTableHeader(0, templateTable,
    891       tmpTable);
    892     table.setHeader(adaptedHeader);
    893     // Adapt directory table data to template table
    894     for (Row row : tmpTable.getRows())
    895     {
    896       // Clear checkbox if navigating to target directory
    897       if (selectMoveDir != null && selectMoveDir)
    898       {
    899         row.getCells().get(0).setValue(null);
    900       }
    901       // Add slash to directory names
    902       Cell nameCell = row.getCells().get(1);
    903       String dirName = (String) nameCell.getValue();
    904       nameCell.setValue(dirName + "/");
    905       // For column 2 and upwards, add empty cells if necessary.
    906       // row = adaptTableRow(row, 2, templateTable, tmpTable);
    907       row = adaptTableRow(row, 2, templateTable, tmpTable);
    908       table.getRows().add(0, row);
    909     }
    910     Directory parentDir = dir.getParent();
    911     if (!dir.isRootDirectory() && parentDir != null && !parentDir
    912       .isRootDirectory())
    913     {
    914       // Prepend parent directory row
    915       Row parentDirRow = tfactory.createRow(parentDir);
    916       // Clear checkbox
    917       parentDirRow.getCells().get(0).setValue(null);
    918       // Add slash to directory names
    919       Cell nameCell = parentDirRow.getCells().get(1);
    920       nameCell.setValue("../");
    921       // For column 2 and upwards, add empty cells if necessary.
    922       // parentDirRow = adaptTableRow(parentDirRow, 2, templateTable,
    923       // tmpTable);
    924       parentDirRow = adaptTableRow(parentDirRow, 2, templateTable,
    925         tmpTable);
    926       table.getRows().add(0, parentDirRow);
    927     }
    928     return table;
    929   }
    930 
    931 
    932   /**
    933    * Adapts a table header for source items so it fits in a table for template
    934    * items. The tables for source and template items are used to find what
    935    * cells in the source row are applicable in the template table. This is
    936    * done by checking the names for each column. A column in the template
    937    * table that has a corresponding column in the source table will have the
    938    * source cell inserted, otherwise an empty cell. Columns unique to the
    939    * source table will not trigger insertion of a cell.
    940    *
    941    * @param startIndex int Index for first column to check
    942    * @param templateTable Table Table for template items
    943    * @param sourceTable Table Table for source items
    944    * @return List<Column> Output header for source item, modified to fit into
    945    *         template table.
    946    */
    947   @SuppressWarnings("unchecked")
    948   private List<Column> adaptTableHeader(int startIndex, Table templateTable,
    949       Table sourceTable)
    950   {
    951     if (startIndex >= templateTable.getHeader().size())
    952     {
    953       // No columns to adapt, return input header.
    954       return sourceTable.getHeader();
    955     }
    956     /*
    957      * Get hash table of column names and column indices in source table.
    958      */
    959     Hashtable<String, Integer> sourceColumnNameHashtable = new Hashtable<String, Integer>(
    960       0);
    961     for (int i = startIndex; i < sourceTable.getHeader().size(); i++)
    962     {
    963       Column srcc = sourceTable.getHeader().get(i);
    964       String sourceColumnName = srcc.getValue();
    965       if (sourceColumnName != null)
    966       {
    967         // Add source column name to hash table.
    968         sourceColumnNameHashtable.put(sourceColumnName, new Integer(i));
    969         log
    970           .debug("i = " + i + " sourceColumnNameHashtable.get(" + sourceColumnName + ").intValue() = " + sourceColumnNameHashtable
    971             .get(sourceColumnName).intValue());
    972       }
    973     }
    974     /*
    975      * For column startIndex and upwards, only keep source columns for
    976      * columns existing in both source and template tables. Add empty
    977      * columns for columns unique to template table.
    978      */
    979     Table tmpTable = new Table("TemporaryTable");
    980     // Add columns up to startIndex.
    981     for (int i = 0; i < startIndex; i++)
    982     {
    983       Column column = sourceTable.getHeader().get(i);
    984       tmpTable.add(column);
    985       log
    986         .debug("i = " + i + " column \"" + column.getValue() + "\" copied.");
    987     }
    988     /*
    989      * For column startIndex and upwards, add empty columns if necessary.
    990      */
    991     for (int i = startIndex; i < templateTable.getHeader().size(); i++)
    992     {
    993       Column c = templateTable.getHeader().get(i);
    994       // Only add visible columns in template table
    995       if (!c.isVisible())
    996       {
    997         continue;
    998       }
    999       // Check if corresponding source table column exists, if any.
    1000       String templateColumnName = c.getValue();
    1001       if (sourceColumnNameHashtable.containsKey(templateColumnName))
    1002       {
    1003         // Source table column OK
    1004         int sourceColumnIndex = sourceColumnNameHashtable.get(
    1005           templateColumnName).intValue();
    1006         Column column = sourceTable.getHeader().get(sourceColumnIndex);
    1007         // If initial Id column, remove column name
    1008         if (i == 0 && column.getValue().equals("Id"))
    1009         {
    1010           column.setValue("");
    1011         }
    1012         tmpTable.add(column);
    1013         log
    1014           .debug("i = " + i + " templateColumnName = \"" + templateColumnName + "\" column \"" + column
    1015             .getValue() + "\" inserted.");
    1016       }
    1017       else
    1018       {
    1019         // Add new column for template column not in source table
    1020         Column column = new Column(templateColumnName);
    1021         // If initial Id column, remove column name
    1022         if (i == 0 && column.getValue().equals("Id"))
    1023         {
    1024           column.setValue("");
    1025         }
    1026         tmpTable.add(column);
    1027         log
    1028           .debug("i = " + i + " templateColumnName = \"" + templateColumnName + "\" new column \"" + column
    1029             .getValue() + "\" inserted.");
    1030       }
    1031     }
    1032     // Return adapted source header.
    1033     return tmpTable.getHeader();
    1034   }
    1035 
    1036 
    1037   /**
    1038    * Adapts a table row for source items so it fits in a table for template
    1039    * items. The tables for source and template items are used to find what
    1040    * cells in the source row are applicable in the template table. This is
    1041    * done by checking the names for each column. A column in the template
    1042    * table that has a corresponding column in the source table will have the
    1043    * source cell inserted, otherwise an empty cell. Columns unique to the
    1044    * source table will not trigger insertion of a cell.
    1045    *
    1046    * @param row Row Input row from source table to be adapted.
    1047    * @param startIndex int Index for first column to check
    1048    * @param templateTable Table Table for template items
    1049    * @param sourceTable Table Table for source items
    1050    * @return Row Output row for source item, modified to fit into template
    1051    *         table.
    1052    */
    1053   @SuppressWarnings("unchecked")
    1054   private Row adaptTableRow(Row row, int startIndex, Table templateTable,
    1055       Table sourceTable)
    1056   {
    1057     if (startIndex >= row.getCells().size())
    1058     {
    1059       // No cells to adapt, return input row.
    1060       return row;
    1061     }
    1062     /*
    1063      * Get hash table of column names and column indices in source table.
    1064      */
    1065     Hashtable<String, Integer> sourceColumnNameHashtable = new Hashtable<String, Integer>(
    1066       0);
    1067     for (int i = startIndex; i < sourceTable.getHeader().size(); i++)
    1068     {
    1069       Column srcc = sourceTable.getHeader().get(i);
    1070       String sourceColumnName = srcc.getValue();
    1071       if (sourceColumnName != null)
    1072       {
    1073         // Add source column name to hash table.
    1074         sourceColumnNameHashtable.put(sourceColumnName, new Integer(i));
    1075         log
    1076           .debug("i = " + i + " sourceColumnNameHashtable.get(" + sourceColumnName + ").intValue() = " + sourceColumnNameHashtable
    1077             .get(sourceColumnName).intValue());
    1078       }
    1079     }
    1080     /*
    1081      * For column startIndex and upwards, only keep source cells for columns
    1082      * existing in both source and template tables. Add empty cells for
    1083      * columns unique to template table.
    1084      */
    1085     ArrayList<Cell<?>> cellList = new ArrayList<Cell<?>>(0);
    1086     // Add cells up to startIndex.
    1087     for (int i = 0; i < startIndex; i++)
    1088     {
    1089       Cell<?> cell = row.getCells().get(i);
    1090       cellList.add(cell);
    1091       log
    1092         .debug("New row i = " + i + " cell value \"" + cell.getValue() + "\" copied.");
    1093     }
    1094     /*
    1095      * For column startIndex and upwards, add empty cells if necessary.
    1096      */
    1097     Cell emptyCell = new Cell<String>(null);
    1098     for (int i = startIndex; i < templateTable.getHeader().size(); i++)
    1099     {
    1100       Column c = templateTable.getHeader().get(i);
    1101       // Only add visible columns in template table
    1102       if (!c.isVisible())
    1103       {
    1104         continue;
    1105       }
    1106       // Check if corresponding source table cell exists, if any.
    1107       String templateColumnName = c.getValue();
    1108       if (sourceColumnNameHashtable.containsKey(templateColumnName))
    1109       {
    1110         // Source table cell OK
    1111         int sourceCellIndex = sourceColumnNameHashtable.get(
    1112           templateColumnName).intValue();
    1113         Cell<?> cell = row.getCells().get(sourceCellIndex);
    1114         cellList.add(cell);
    1115         log
    1116           .debug("New row i = " + i + " templateColumnName = \"" + templateColumnName + "\" cell value \"" + cell
    1117             .getValue() + "\" inserted.");
    1118       }
    1119       else
    1120       {
    1121         // Add empty cell for template column not in source table
    1122         cellList.add(emptyCell);
    1123         log
    1124           .debug("New row i = " + i + " templateColumnName = \"" + templateColumnName + "\" empty cell inserted.");
    1125       }
    1126     }
    1127     // Construct adapted source row.
    1128     row.setCells(cellList);
    1129     return row;
    1130   }
    1131 
    1132 
    1133   /**
    1134    * Convenience method for fetching the
    1135    * table update button clicked flag.
    1136    *
    1137    * @return boolean The table update button clicked flag.
    1138    */
    1139   private boolean fetchTableUpdateButtonClickedFlag()
    1140   {
    1141     // Get table update button clicked flag
    1142     boolean tableUpdateButtonClicked = false;
    1143     Boolean tableUpdateButtonClickedFlagFromRequest = false;
    1144     try
    1145     {
    1146       tableUpdateButtonClickedFlagFromRequest = getValidBoolean(VTABLEUPDATEBUTTONCLICKED);
    1147       if (tableUpdateButtonClickedFlagFromRequest == null)
    1148       {
    1149         tableUpdateButtonClicked = false;
    1150       }
    1151       else
    1152       {
    1153         tableUpdateButtonClicked = tableUpdateButtonClickedFlagFromRequest;
    1154       }
    1155     }
    1156     catch (Exception e)
    1157     {
    1158       log.debug("Exception when trying to get valid parameter VTABLEUPDATEBUTTONCLICKED: " + e);
    1159     }
    1160     log.debug("tableUpdateButtonClickedFlagFromRequest = " + tableUpdateButtonClickedFlagFromRequest + " tableUpdateButtonClicked = " + tableUpdateButtonClicked);
    1161     //
    1162     log.debug("tableUpdateButtonClicked = " + tableUpdateButtonClicked);
    1163     return tableUpdateButtonClicked;
    1164   }
     94    /**
     95        * Session identifier for an active directory
     96    */
     97    public static final VInteger VDIRID = new VInteger("active.dir.id", 1, true);
     98    public static final VBoolean VSELECT = new VBoolean("select", true);
     99    public static final VBoolean VSELECTMOVEDIR = new VBoolean(
     100    "select.move.dir", false);
     101    public static final VBoolean VMOVEFILESSTART = new VBoolean("moveFilesStart", false);
     102    public static final VBoolean VMOVEFILES = new VBoolean("moveFiles", false);
     103    public static final VBoolean VTABLEUPDATEBUTTONCLICKED = new VBoolean("tableUpdateButtonClicked", false);
     104   
     105    /**
     106        * Creates a layout for viewing/selecting the contents of a directory. The
     107        * details of what the layout contains depends on Boolean flags transferred
     108        * as valid parameters, that indicate the purpose of the directory listing.
     109        * The general layout consists of a directory table and a file table. The
     110        * directory table has two tabs, a 'contents' tab and a 'properties' tab.
     111        * The directory 'contents' tab shows a list of sub-directories in the
     112        * current directory, as well as a link to the parent directory. The file
     113        * table shows a list of files in the current directory. The file table may
     114        * be configured by the user via a popup window, and also has a filter row
     115        * below the table header.
     116    */
     117    @Override
     118    protected void runMe()
     119    throws ActionException, InvalidParameterValue
     120    {
     121        log.debug("Start");
     122        // Define
     123        Boolean select, selectMoveDir, moveFilesStart, moveFilesMode = null;
     124        String actionId;
     125        DbControl dc;
     126        Integer itemId, start, max;
     127        ItemQuery<File> query;
     128        Directory rootDir;
     129        User user;
     130        ItemFactory factory;
     131        List<String> columnOrder;
     132        Project activeP;
     133        QueryFactory qf;
     134        //
     135        // Fetch table update button clicked flag
     136        boolean tableUpdateButtonClicked = fetchTableUpdateButtonClickedFlag();
     137        log.debug("tableUpdateButtonClicked = " + tableUpdateButtonClicked);
     138        // Create
     139        // Check if user has selected file[s] in directory table to move
     140        moveFilesStart = getValidBoolean(VMOVEFILESSTART);
     141        if (moveFilesStart == null)
     142        {
     143            moveFilesStart = false;
     144            log
     145            .debug("Input moveFilesStart == null, reset to moveFilesStart = " + moveFilesStart);
     146        }
     147        log.debug("moveFilesStart = " + moveFilesStart);
     148        if (moveFilesStart)
     149        {
     150            // Check input
     151            List<Integer> tmpFileIds = getValidIntegerList(ItemIdField.VPARAM);
     152            log.debug("tmpFileIds from ItemIdField.VPARAM for input check = " + tmpFileIds);
     153            if (tmpFileIds != null && tmpFileIds.size() > 0)
     154            {
     155                setSessionAttribute(VSELECT, true);
     156                setSessionAttribute(VSELECTMOVEDIR, true);
     157                setSessionAttribute(VMOVEFILES, true);
     158                setSessionAttribute(ForwardField.VPARAM, MoveFiles.class.getName());
     159            }
     160            else
     161            {
     162                setError("Select at least one file to move");
     163            }
     164        }
     165        select = getSessionAttribute(VSELECT);
     166        actionId = getSessionAttribute(ForwardField.VPARAM);
     167        selectMoveDir = getSessionAttribute(VSELECTMOVEDIR);
     168        moveFilesMode = getSessionAttribute(VMOVEFILES);
     169        qf = getQueryFactory();
     170        dc = newDbControl();
     171        activeP = getActiveProject(dc);
     172        // Use
     173        if (selectMoveDir == null)
     174        {
     175            selectMoveDir = false;
     176            log
     177            .debug("Input selectMoveDir == null, reset to selectMoveDir = " + selectMoveDir);
     178        }
     179        if (moveFilesMode == null)
     180        {
     181            moveFilesMode = false;
     182            log
     183            .debug("Input moveFilesMode == null, reset to moveFilesMode = " + moveFilesMode);
     184        }
     185        log.debug("select = " + select + " selectMoveDir = " + selectMoveDir + " moveFilesMode = " + moveFilesMode);
     186        /***********************************************************************
     187            * Create file table
     188        */
     189        // A user clicked a directory
     190        itemId = getSessionAttribute(ViewActiveDirectory.VDIRID);
     191        if (itemId == null)
     192        {
     193            // No directory selected, first time
     194            user = getOwner();
     195            dc.reattachItem(user);
     196            rootDir = user.getHomeDirectory();
     197        }
     198        else
     199        {
     200            factory = getItemFactory(dc);
     201            rootDir = factory.getById(Directory.class, itemId);
     202        }
     203        // Query with parameters
     204        query = rootDir.getFileQuery();
     205        start = 0;
     206        max = 1000000000;
     207        columnOrder = getValidStringList(ConfigureTableFactory2.VCOLUMNORDER);
     208        // Use
     209        setAttribute(ConfigureTableFactory2.VDATACLASS, FileData.class
     210        .getName());
     211        setAttribute(ConfigureTableFactory2.VWRAPPERCLASS, File.class.getName());
     212        // Configure TableFactory2
     213        ConfigureTableFactory2 confTF2 = new ConfigureTableFactory2(getOwner());
     214        confTF2.setExternalTableUpdateButtonClicked(tableUpdateButtonClicked);
     215        TableFactory2 tableFactory2 = confTF2.configure(dc, File.class,
     216        FileData.class, query, start, max, columnOrder, this, this
     217        .getTableFactory2());
     218        // Create file table
     219        Table fileTable = tableFactory2.build();
     220        // Add asPopup parameter to hide the menu in the next step. This is needed when the action is used
     221        // in the wizard
     222        if (getActionFactory().getAsPopup())
     223        {
     224            TextField<Boolean> asPopup = new TextField<Boolean>(
     225            ActionFactory.VPOPUP);
     226            asPopup.setHidden(true);
     227            asPopup.setValue(true);
     228            fileTable.add(asPopup);
     229        }
     230       
     231        /**
     232            * If in the top level of the project, add all files visible to the
     233            * project, but which are not in an accessible directory
     234        */
     235        if (activeP != null && activeP.getProjectDirectory() != null && activeP.getProjectDirectory().equals(rootDir))
     236        {
     237            log.debug("Checking for exclude directories");
     238            query = qf.select(File.class);
     239            query.exclude(Include.MINE);
     240            query.include(Include.IN_PROJECT);
     241            ItemQuery<Directory> dirQuery = qf.select(Directory.class);
     242            dirQuery.exclude(Include.MINE);
     243            dirQuery.include(Include.IN_PROJECT);
     244            List<Directory> allDirs = dirQuery.list(dc);
     245            // Specifically add the current dir so that files are not repeated
     246            query.restrictPermanent(Restrictions.neq(Hql.property("directory"),
     247            Hql.entity(rootDir)));
     248            for (Directory currentDir : allDirs)
     249            {
     250                log.debug("Excluded dir: " + currentDir.getName());
     251                query.restrictPermanent(Restrictions.neq(Hql
     252                .property("directory"), Hql.entity(currentDir)));
     253            }
     254            tableFactory2 = confTF2.configure(dc, File.class, FileData.class,
     255            query, start, max, columnOrder, this, this.getTableFactory2());
     256            Table newTable = tableFactory2.build();
     257            for (Row r : newTable.getRows())
     258            {
     259                r.getTags().add("shared");
     260                fileTable.addRow(r);
     261            }
     262        }
     263        fileTable.setTitle("Files");
     264        // Only add file view action if no dedicated file selection
     265        if (select == null || select)
     266        {
     267            /*
     268                * Column actions are transferred to cells in rows, when the table
     269                * is built.
     270            */
     271            for (Row row : fileTable.getRows())
     272            {
     273                for (Cell<?> cell : row.getCells())
     274                {
     275                    cell.setActionLink(null);
     276                }
     277            }
     278        }
     279        //
     280        fileTable.add(new TextField<String>(ConfigureTableFactory2.VWRAPPERCLASS, File.class.getName()));
     281        fileTable.add(new TextField<String>(ConfigureTableFactory2.VDATACLASS, FileData.class.getName()));
     282        // Add query parameters
     283        fileTable.add(new TextField<Integer>(ConfigureTableFactory2.VQUERYSTARTAT, start));
     284        // Set forward action
     285        fileTable.add(new TextField<String>(ConfigureTableFactory2.VFORWARDTO, ViewActiveDirectory.class.getName()));
     286        // Set this action as the table configuration action
     287        fileTable.setConfigureTableAction(getActionFactory().getActionLink(
     288        ConfigureTableFactory2.class, ""));
     289        // We do not use the scroller when browsing for files
     290        fileTable.setScroller(null);
     291        // Add column order
     292        List<Column> header = fileTable.getHeader();
     293        for (int i = 0; i < header.size(); i++)
     294        {
     295            AttributeDefinition ad = header.get(i).getAttributeDefinition();
     296            fileTable.add(new TextField<String>(ConfigureTableFactory2.VCOLUMNORDER, ad.getKey()));
     297        }
     298        // Add class name needed for delete action
     299        fileTable.add(new TextField<String>(FormFactory.VCLASSNAME, File.class.getName()));
     300        // Add optional form title
     301        String formTitle = fetchFormTitle(select, selectMoveDir);
     302        fileTable.add(new TitleField(formTitle));
     303        // Add optional special name for "Next" button
     304        String nextButtonName = fetchNextButtonName(select, selectMoveDir);
     305        fileTable.add(new NextButtonNameField(nextButtonName));
     306        // Use getRequest().getAttribute("table") in a
     307        // subsequent action to get the created table.
     308        //
     309        // Add update button
     310        Toolbar fileToolbar = new Toolbar();
     311        fileTable.setToolbar(fileToolbar);
     312        ActionLink update = getActionFactory().getActionLink(
     313        ViewActiveDirectory.class, "Update");
     314        update.addParameter(VTABLEUPDATEBUTTONCLICKED, true);
     315        fileToolbar.add(update);
     316        //
     317        String path = rootDir.getPath().toString();
     318        fileTable.setTitle(fileTable.getTitle());
     319        //
     320        ClassDescriptor wrapperDescriptor = new ClassDescriptor(File.class);
     321        setAttribute("table", fileTable);
     322        setAttribute("tableQuery", query);
     323        setAttribute("header", header);
     324        setAttribute("wrapperDescriptor", wrapperDescriptor);
     325        /*
     326            * Directory table
     327        */
     328        // prependDirectories(fileTable, rootDir, select, selectMoveDir);
     329        Table dirTable = createDirectoryTable(fileTable, rootDir, select,
     330        selectMoveDir, moveFilesMode, moveFilesStart);
     331        Toolbar dirToolbar = new Toolbar();
     332        dirTable.setToolbar(dirToolbar);
     333        dirTable.add(new TextField<String>(ConfigureTableFactory2.VWRAPPERCLASS, Directory.class.getName()));
     334        // We do not use the scroller when browsing for directories
     335        dirTable.setScroller(null);
     336        //
     337        TabSet ts = null;
     338        Title title = null;
     339        /***********************************************************************
     340            * Directory content form
     341        */
     342        if (select == null || select)
     343        {
     344            // Get optional special title for file selection form
     345            formTitle = fetchFormTitle(select, selectMoveDir);
     346            // Get optional special name for "Next" button
     347            nextButtonName = fetchNextButtonName(select, selectMoveDir);
     348            /*
     349                * If selection is for directory to move file to, override above.
     350            */
     351            if (selectMoveDir)
     352            {
     353                // Add button to directory table tool bar
     354                // Remove default buttons
     355                dirToolbar.list().clear();
     356                // dirToolbar.clear();
     357                // Add a possibly renamed "Next" button
     358                ActionLink al = new ActionLink(nextButtonName, actionId);
     359                dirToolbar.setDefaultAction(al);
     360                dirToolbar.add(al);
     361                /*
     362                    * Moving several files
     363                */
     364                log.debug("moveFilesMode = " + moveFilesMode);
     365                if (moveFilesMode)
     366                {
     367                    /*
     368                        * This action may be called several times when
     369                        * navigating from the source to the target directory.
     370                        * First time the id values for selected files are
     371                        * stored in the default valid parameter VInteger ItemIdField.VPARAM,
     372                        * otherwise they are stored in valid parameter VInteger ViewActiveFile.VFILEID.
     373                    */
     374                    List<Integer> tmpFileIds = null;
     375                    // Check if first time when navigating to target directory
     376                    if (moveFilesStart)
     377                    {
     378                        tmpFileIds = getValidIntegerList(ItemIdField.VPARAM);
     379                        log.debug("tmpFileIds from ItemIdField.VPARAM = " + tmpFileIds);
     380                    }
     381                    else
     382                    {
     383                        tmpFileIds = getValidIntegerList(ViewActiveFile.VFILEID);
     384                        log.debug("tmpFileIds from ViewActiveFile.VFILEID = " + tmpFileIds);
     385                    }
     386                    log.debug("tmpFileIds = " + tmpFileIds);
     387                    // Add id values for selected files as parameters to action link
     388                    if (tmpFileIds != null && tmpFileIds.size() > 0)
     389                    {
     390                        // Set id values for source files
     391                        for (Integer fileId : tmpFileIds)
     392                        {
     393                            getFormFactory().addHiddenField(dirTable, ViewActiveFile.VFILEID, fileId);
     394                        }
     395                    }
     396                }
     397            }
     398            title = new Title(formTitle);
     399            // Add button to file table tool bar
     400            // Remove default buttons
     401            fileToolbar.list().clear();
     402            fileToolbar.clear();
     403            // Add update button
     404            fileToolbar.add(update);
     405            // Add a possibly renamed "Next" button
     406            ActionLink al = new ActionLink(nextButtonName, actionId);
     407            // fileToolbar.setDefaultAction(al);
     408            fileToolbar.setDefaultAction(update);
     409            fileToolbar.add(al);
     410            log.debug("(2) fileToolbar.getDefaultAction() = " + fileToolbar
     411            .getDefaultAction());
     412        }
     413        else
     414        {
     415            title = new Title("Files");
     416            // Simple browsing of the directory
     417            // Button for new directory
     418            ActionLink newDirectoryBtn = getActionFactory().getActionLink(
     419            NewDirectory.class, "NewDirectory");
     420            dirToolbar.add(newDirectoryBtn);
     421            // Button for deleting directory
     422            ActionLink deleteDirectoryBtn = getActionFactory().getActionLink(
     423            DeleteDirectory.class, "DeleteDirectory");
     424            dirToolbar.add(deleteDirectoryBtn);
     425            // Add directory tool bar
     426            dirTable.setToolbar(dirToolbar);
     427            // Simple browsing of the directory
     428            // Button for moving file[s]
     429            ActionLink moveAction = getActionFactory().getActionLink(
     430            ViewActiveDirectory.class, "Move");
     431            moveAction.addParameter(VMOVEFILESSTART, true);
     432            fileToolbar.add(moveAction);
     433            if (fileTable.getRows().size() == 0)
     434            {
     435                moveAction.disable();
     436            }
     437            // Button for deleting file
     438            ActionLink deleteAction = getActionFactory().getActionLink(
     439            DeleteItems.class, "Delete");
     440            fileToolbar.add(deleteAction);
     441            if (fileTable.getRows().size() == 0)
     442            {
     443                deleteAction.disable();
     444            }
     445            // Button for sharing directory
     446            PopupLink shareAction = new PopupLink();
     447            GUIElement<?> popupContent = ShareToProject.createPermissionForm(true);
     448            shareAction.setContent(popupContent);
     449            shareAction.setLabel("UseInProject");
     450            // Button for sharing file
     451            PopupLink shareFileAction = new PopupLink();
     452            GUIElement<?> popupContent2 = ShareToProject.createPermissionForm(false);
     453            shareFileAction.setContent(popupContent2);
     454            shareFileAction.setLabel("UseInProject");
     455                       
     456            if (dc.getSessionControl().getActiveProjectId() == 0)
     457            {
     458                shareAction.disable();
     459                shareFileAction.disable();
     460            }
     461            dirToolbar.add(shareAction);
     462            fileToolbar.add(shareFileAction);
     463            // Button for uploading file
     464            ActionLink upload = getActionFactory().getActionLink(NewFile.class,
     465            "UploadFile");
     466            fileToolbar.add(upload);
     467            log.debug("(3) fileToolbar.getDefaultAction() = " + fileToolbar
     468            .getDefaultAction());
     469            /*******************************************************************
     470                * Directory content container
     471            */
     472            RowContainer contentContainer = new RowContainer();
     473            contentContainer.add(dirTable);
     474            contentContainer.add(fileTable);
     475            /*******************************************************************
     476                * Directory properties form
     477            */
     478            Form propertiesForm = getFormFactory().getForm(Directory.class,
     479            rootDir);
     480            // Toolbar
     481            Toolbar dirToolbar2 = new Toolbar();
     482            dirToolbar2.add(getActionFactory().getActionLink(
     483            SaveDirectory.class, "Save"));
     484            propertiesForm.setToolbar(dirToolbar2);
     485            /*******************************************************************
     486                * Directory extensions
     487            */
     488            @SuppressWarnings("unused")
     489            List<DirectoryContext> directoryContexts = getRegistry()
     490            .getContexts(DirectoryContext.class);
     491            if (directoryContexts == null)
     492            {
     493                log.debug("directoryContexts = null");
     494            }
     495            else
     496            {
     497                log.debug("directoryContexts.size() = " + directoryContexts
     498                .size());
     499            }
     500            if (!directoryContexts.isEmpty())
     501            {
     502                Table dirExtTable = new Table("dirExtensionsTable");
     503                List<Column> dirExtHeader = new ArrayList<Column>(2);
     504                Column<String> name = new Column<String>("Name");
     505                dirExtHeader.add(name);
     506                Column<String> description = new Column<String>("Description");
     507                dirExtHeader.add(description);
     508                dirExtTable.setHeader(dirExtHeader);
     509                int rowId = 0;
     510                for (DirectoryContext context : directoryContexts)
     511                {
     512                    rowId++;
     513                    Row row = new Row(rowId);
     514                    // Name column
     515                    log.debug("context.getLabel() = \"" + context.getLabel() + "\"");
     516                    Cell<String> nameCell = new Cell<String>(context.getLabel());
     517                    AbstractLink link = context
     518                    .getActionLink(getActionFactory());
     519                    // Link the extensions so that when one is selected the
     520                    // files table/form is posted to the given action.
     521                    CrossLink postTableLink = new CrossLink(dirTable, link);
     522                    nameCell.setActionLink(postTableLink);
     523                    row.addCell(nameCell);
     524                    // Description column
     525                    log.debug("context.getDescription() = \"" + context.getDescription() + "\"");
     526                    Cell<String> descCell = new Cell<String>(context.getDescription());
     527                    descCell.setActionLink(postTableLink);
     528                    row.addCell(descCell);
     529                    //
     530                    dirExtTable.addRow(row);
     531                }
     532                PopupLink dirExtensions = new PopupLink();
     533                TitledWindow popup = new TitledWindow(
     534                "ExtensionsForDirectories");
     535                popup.setStatic(false);
     536                popup.setContent(dirExtTable);
     537                dirExtensions.setLabel("ExtensionsForDirectories");
     538                dirExtensions.setContent(popup);
     539                dirToolbar.add(dirExtensions);
     540            }
     541            /*******************************************************************
     542                * File extensions
     543            */
     544            @SuppressWarnings("unused")
     545            List<FileContext> fileContexts = getRegistry().getContexts(
     546            FileContext.class);
     547            if (fileContexts == null)
     548            {
     549                log.debug("fileContexts = null");
     550            }
     551            else
     552            {
     553                log.debug("fileContexts.size() = " + fileContexts.size());
     554            }
     555            if (!fileContexts.isEmpty())
     556            {
     557                Table fileExtTable = new Table("fileExtensionsTable");
     558                List<Column> fileExtHeader = new ArrayList<Column>(2);
     559                Column<String> name = new Column<String>("Name");
     560                fileExtHeader.add(name);
     561                Column<String> description = new Column<String>("Description");
     562                fileExtHeader.add(description);
     563                fileExtTable.setHeader(fileExtHeader);
     564                int rowId = 0;
     565                for (FileContext context : fileContexts)
     566                {
     567                    rowId++;
     568                    Row row = new Row(rowId);
     569                    // Name column
     570                    log.debug("context.getLabel() = \"" + context.getLabel() + "\"");
     571                    Cell<String> nameCell = new Cell<String>(context.getLabel());
     572                    AbstractLink link = context
     573                    .getActionLink(getActionFactory());
     574                    // Link the extensions so that when one is selected the
     575                    // files table/form is posted to the given action.
     576                    CrossLink postTableLink = new CrossLink(fileTable, link);
     577                    nameCell.setActionLink(postTableLink);
     578                    row.addCell(nameCell);
     579                    // Description column
     580                    log.debug("context.getDescription() = \"" + context.getDescription() + "\"");
     581                    Cell<String> descCell = new Cell<String>(context.getDescription());
     582                    descCell.setActionLink(postTableLink);
     583                    row.addCell(descCell);
     584                    //
     585                    fileExtTable.addRow(row);
     586                }
     587                TitledWindow popup = new TitledWindow("ExtensionsForFiles");
     588                popup.setStatic(false);
     589                popup.setContent(fileExtTable);
     590                PopupLink fileExtensions = new PopupLink();
     591                fileExtensions.setLabel("ExtensionsForFiles");
     592                fileExtensions.setContent(popup);
     593                fileToolbar.add(fileExtensions);
     594            }
     595            /*******************************************************************
     596                * Tab set
     597            */
     598            ts = new TabSet();
     599            // Content tab
     600            Tab contentTab = new Tab("Content", "dirContent");
     601            contentTab.setGuiElement(contentContainer);
     602            contentTab.setSelected(true);
     603            ts.add(contentTab);
     604            // Properties tab
     605            Tab propertiesTab = new Tab("Properties", "dirProperties");
     606            propertiesTab.setGuiElement(propertiesForm);
     607            ts.add(propertiesTab);
     608        }
     609        /***********************************************************************
     610            * Layout
     611        */
     612        RowLayout layout = getLayoutFactory().getRowLayout();
     613        layout.add(title);
     614        // Directory tab set
     615        if (ts != null)
     616        {
     617            layout.add(ts);
     618        }
     619        else
     620        {
     621            if (selectMoveDir)
     622            {
     623                layout.add(dirTable);
     624            }
     625            else
     626            {
     627                layout.add(dirTable);
     628                // Add file table
     629                layout.add(fileTable);
     630            }
     631        }
     632        //
     633        setLayout(layout);
     634    }
     635   
     636    /**
     637        * Obtains title for file/directory selection form from valid parameter.
     638        *
     639        * @param select Boolean Indicates file selection
     640        * @param selectMoveDir Boolean Indicates directory selection
     641        * @return String Title for file selection form
     642    */
     643    @SuppressWarnings("unchecked")
     644    private String fetchFormTitle(Boolean select, Boolean selectMoveDir)
     645    {
     646        String formTitle = null;
     647        if (select == null || select)
     648        {
     649            // Get optional special title for file selection form
     650            try
     651            {
     652                formTitle = getString(TitleField.VPARAM);
     653            }
     654            catch (InvalidParameterValue e)
     655            {}
     656            if (formTitle == null || formTitle.equals(""))
     657            {
     658                formTitle = getSessionAttribute(TitleField.VPARAM);
     659            }
     660            if (formTitle == null || formTitle.equals(""))
     661            {
     662                formTitle = new String("Select file[s]");
     663            }
     664            // If selection is for directory to move file to, override above
     665            if (selectMoveDir)
     666            {
     667                formTitle = new String("Move to target directory");
     668            }
     669        }
     670        return formTitle;
     671    }
     672   
     673    /**
     674        * Obtains name for for "Next" button in file/directory selection form from
     675        * valid parameter.
     676        *
     677        * @param select Boolean Indicates file selection
     678        * @param selectMoveDir Boolean Indicates directory selection
     679        * @return String Name for "Next" button in file selection form
     680    */
     681    @SuppressWarnings("unchecked")
     682    private String fetchNextButtonName(Boolean select, Boolean selectMoveDir)
     683    {
     684        String nextButtonName = null;
     685        if (select == null || select)
     686        {
     687            // Get optional special name for "Next" button
     688            try
     689            {
     690                nextButtonName = getString(NextButtonNameField.VPARAM);
     691            }
     692            catch (InvalidParameterValue e)
     693            {}
     694            if (nextButtonName == null || nextButtonName.equals(""))
     695            {
     696                nextButtonName = getSessionAttribute(NextButtonNameField.VPARAM);
     697            }
     698            if (nextButtonName == null || nextButtonName.equals(""))
     699            {
     700                nextButtonName = new String("Next");
     701            }
     702            // If selection is for directory to move file to, override above
     703            if (selectMoveDir)
     704            {
     705                nextButtonName = new String("Next");
     706            }
     707        }
     708        return nextButtonName;
     709    }
     710   
     711    /**
     712        * Creates a directory table showing sub-directories in current directory,
     713        * as well as a link to parent directory. The table columns are defined by
     714        * the template table.
     715        *
     716        * @param templateTable Table Template table for selecting columns.
     717        * @param dir Directory Source directory.
     718        * @param select Boolean Flag indicating file selection mode.
     719        * @param selectMoveDir Boolean Flag indicating directory selection mode
     720        *        (overrides file selection mode).
     721        * @param moveFilesMode Boolean Flag indicating file batch move mode.
     722        * @param moveFilesStart Boolean Flag indicating file batch move start.
     723        * @return Table
     724    */
     725    @SuppressWarnings("unchecked")
     726    private Table createDirectoryTable(Table templateTable, Directory dir,
     727    Boolean select, Boolean selectMoveDir, Boolean moveFilesMode, Boolean moveFilesStart)
     728    {
     729        // Define
     730        ItemQuery<Directory> query;
     731        TableFactory tfactory;
     732        DbControl dc;
     733        Project activeP;
     734        QueryFactory qf;
     735        String path = dir.getPath().toString();
     736        // Create
     737        qf = getQueryFactory();
     738        dc = newDbControl();
     739        activeP = getActiveProject(dc);
     740        tfactory = getTableFactory();
     741        tfactory.setDbControl(dc);
     742        query = dir.getSubDirectories();
     743        if (activeP != null)
     744        {
     745            query.include(Include.IN_PROJECT);
     746        }
     747        tfactory.reset();
     748        tfactory.setDbControl(dir.getDbControl());
     749        tfactory.setItemClass(Directory.class);
     750        tfactory.setQuery(query);
     751        // Allow unlimited number of rows in table
     752        tfactory.setMaxResults(0);
     753        ActionLink clickAction = null;
     754        if (select == null || select)
     755        {
     756            // Get optional special title for file selection form
     757            String formTitle = fetchFormTitle(select, selectMoveDir);
     758            // Get optional special name for "Next" button
     759            String nextButtonName = fetchNextButtonName(select, selectMoveDir);
     760            clickAction = getActionFactory().getActionLink(SelectFile.class,
     761            "View");
     762            clickAction
     763            .addParameter(TitleField.VPARAM, formTitle);
     764            clickAction.addParameter(NextButtonNameField.VPARAM,
     765            nextButtonName);
     766            if (moveFilesMode)
     767            {
     768                /*
     769                    * This action may be called several times when
     770                    * navigating from the source to the target directory.
     771                    * First time the id values for selected files are
     772                    * stored in the default valid parameter VInteger ItemIdField.VPARAM,
     773                    * otherwise they are stored in valid parameter VInteger ViewActiveFile.VFILEID.
     774                */
     775                List<Integer> tmpFileIds = null;
     776                // Check if first time when navigating to target directory
     777                if (moveFilesStart)
     778                {
     779                    try
     780                    {
     781                        tmpFileIds = getValidIntegerList(ItemIdField.VPARAM);
     782                    }
     783                    catch (Exception e)
     784                    {
     785                        log.debug("Exception when trying to retrieve file id list from ItemIdField.VPARAM: " + e);
     786                    }
     787                    log.debug("tmpFileIds from ItemIdField.VPARAM = " + tmpFileIds);
     788                }
     789                else
     790                {
     791                    try
     792                    {
     793                        tmpFileIds = getValidIntegerList(ViewActiveFile.VFILEID);
     794                    }
     795                    catch (Exception e)
     796                    {
     797                        log.debug("Exception when trying to retrieve file id list from ViewActiveFile.VFILEID: " + e);
     798                    }
     799                    log.debug("tmpFileIds from ViewActiveFile.VFILEID = " + tmpFileIds);
     800                }
     801                log.debug("tmpFileIds = " + tmpFileIds);
     802                // Add id values for selected files as parameters to click action
     803                if (tmpFileIds != null && tmpFileIds.size() > 0)
     804                {
     805                    // Set id values for source files
     806                    for (Integer fileId : tmpFileIds)
     807                    {
     808                        clickAction.addParameter(ViewActiveFile.VFILEID, fileId);
     809                    }
     810                }
     811            }
     812        }
     813        else
     814        {
     815            clickAction = getActionFactory().getActionLink(ViewDirectory.class,
     816            "View");
     817        }
     818        tfactory.setColumnAction("Name", clickAction);
     819        Table tmpTable = tfactory.build();
     820        /**
     821            * If in the top level of the project, also show directories that are
     822            * shared to the project, but originate in other projects
     823        */
     824        if (activeP != null && activeP.getProjectDirectory().equals(dir))
     825        {
     826            dir.getProjectKey();
     827            query = qf.select(Directory.class);
     828            query.exclude(Include.MINE);
     829            query.include(Include.IN_PROJECT);
     830            List<Directory> allDirs = query.list(dc);
     831            List<Integer> excludeDirs = new ArrayList<Integer>();
     832            boolean use = false;
     833            // Only list the top directories, do not include the current dir or
     834            // directories with it as parent
     835            for (Directory currentDir : allDirs)
     836            {
     837                if (!allDirs.contains(currentDir.getParent()) && !currentDir
     838                .equals(dir) && !currentDir.getParent().equals(dir))
     839                {
     840                    log.debug("Included dir: " + currentDir.getName());
     841                    use = true;
     842                }
     843                else
     844                {
     845                    excludeDirs.add(currentDir.getId());
     846                    log.debug("Excluded dir: " + currentDir.getName());
     847                }
     848            }
     849            query.reset();
     850            // Add directories if there are any
     851            if (use)
     852            {
     853                for (Integer id : excludeDirs)
     854                {
     855                    query.restrict(Restrictions.neq(Hql.property("id"),
     856                    Expressions.integer(id.intValue())));
     857                }
     858                tfactory.setQuery(query);
     859                Table tabletop = tfactory.build();
     860                for (Row r : tabletop.getRows())
     861                {
     862                    r.getTags().add("shared");         
     863                }
     864                // Merge the tables
     865                for (Row r : tmpTable.getRows())
     866                {
     867                    tabletop.addRow(r);
     868                }
     869                tmpTable = tabletop;
     870            }
     871        }
     872        // Create adapted directory table
     873        Table table = new Table("DirectoryTable");
     874        // Set title explicitly, to get correct plural for "Directory"
     875        table.setTitle("Directory");
     876        table.setSubtitle(path);
     877        // Adapt header to template table
     878        /*
     879            * Simply using the template header,
     880            * table.setHeader(templateTable.getHeader()); would work if the latter
     881            * did not include an appended filter row.
     882        */
     883        List<Column> adaptedHeader = adaptTableHeader(0, templateTable,
     884        tmpTable);
     885        table.setHeader(adaptedHeader);
     886        // Adapt directory table data to template table
     887        for (Row row : tmpTable.getRows())
     888        {
     889            // Clear checkbox if navigating to target directory
     890            if (selectMoveDir != null && selectMoveDir)
     891            {
     892                row.getCells().get(0).setValue(null);
     893            }
     894            // Add slash to directory names
     895            Cell nameCell = row.getCells().get(1);
     896            String dirName = (String) nameCell.getValue();
     897            nameCell.setValue(dirName + "/");
     898            // For column 2 and upwards, add empty cells if necessary.
     899            // row = adaptTableRow(row, 2, templateTable, tmpTable);
     900            row = adaptTableRow(row, 2, templateTable, tmpTable);
     901            table.getRows().add(0, row);
     902        }
     903        Directory parentDir = dir.getParent();
     904        if (!dir.isRootDirectory() && parentDir != null && !parentDir
     905        .isRootDirectory())
     906        {
     907            // Prepend parent directory row
     908            Row parentDirRow = tfactory.createRow(parentDir);
     909            // Clear checkbox
     910            parentDirRow.getCells().get(0).setValue(null);
     911            // Add slash to directory names
     912            Cell nameCell = parentDirRow.getCells().get(1);
     913            nameCell.setValue("../");
     914            // For column 2 and upwards, add empty cells if necessary.
     915            // parentDirRow = adaptTableRow(parentDirRow, 2, templateTable,
     916            // tmpTable);
     917            parentDirRow = adaptTableRow(parentDirRow, 2, templateTable,
     918            tmpTable);
     919            table.getRows().add(0, parentDirRow);
     920        }
     921        return table;
     922    }
     923   
     924    /**
     925        * Adapts a table header for source items so it fits in a table for template
     926        * items. The tables for source and template items are used to find what
     927        * cells in the source row are applicable in the template table. This is
     928        * done by checking the names for each column. A column in the template
     929        * table that has a corresponding column in the source table will have the
     930        * source cell inserted, otherwise an empty cell. Columns unique to the
     931        * source table will not trigger insertion of a cell.
     932        *
     933        * @param startIndex int Index for first column to check
     934        * @param templateTable Table Table for template items
     935        * @param sourceTable Table Table for source items
     936        * @return List<Column> Output header for source item, modified to fit into
     937        *         template table.
     938    */
     939    @SuppressWarnings("unchecked")
     940    private List<Column> adaptTableHeader(int startIndex, Table templateTable,
     941    Table sourceTable)
     942    {
     943        if (startIndex >= templateTable.getHeader().size())
     944        {
     945            // No columns to adapt, return input header.
     946            return sourceTable.getHeader();
     947        }
     948        /*
     949            * Get hash table of column names and column indices in source table.
     950        */
     951        Hashtable<String, Integer> sourceColumnNameHashtable = new Hashtable<String, Integer>(
     952        0);
     953        for (int i = startIndex; i < sourceTable.getHeader().size(); i++)
     954        {
     955            Column srcc = sourceTable.getHeader().get(i);
     956            String sourceColumnName = srcc.getValue();
     957            if (sourceColumnName != null)
     958            {
     959                // Add source column name to hash table.
     960                sourceColumnNameHashtable.put(sourceColumnName, new Integer(i));
     961                log
     962                .debug("i = " + i + " sourceColumnNameHashtable.get(" + sourceColumnName + ").intValue() = " + sourceColumnNameHashtable
     963                .get(sourceColumnName).intValue());
     964            }
     965        }
     966        /*
     967            * For column startIndex and upwards, only keep source columns for
     968            * columns existing in both source and template tables. Add empty
     969            * columns for columns unique to template table.
     970        */
     971        Table tmpTable = new Table("TemporaryTable");
     972        // Add columns up to startIndex.
     973        for (int i = 0; i < startIndex; i++)
     974        {
     975            Column column = sourceTable.getHeader().get(i);
     976            tmpTable.add(column);
     977            log
     978            .debug("i = " + i + " column \"" + column.getValue() + "\" copied.");
     979        }
     980        /*
     981            * For column startIndex and upwards, add empty columns if necessary.
     982        */
     983        for (int i = startIndex; i < templateTable.getHeader().size(); i++)
     984        {
     985            Column c = templateTable.getHeader().get(i);
     986            // Only add visible columns in template table
     987            if (!c.isVisible())
     988            {
     989                continue;
     990            }
     991            // Check if corresponding source table column exists, if any.
     992            String templateColumnName = c.getValue();
     993            if (sourceColumnNameHashtable.containsKey(templateColumnName))
     994            {
     995                // Source table column OK
     996                int sourceColumnIndex = sourceColumnNameHashtable.get(
     997                templateColumnName).intValue();
     998                Column column = sourceTable.getHeader().get(sourceColumnIndex);
     999                // If initial Id column, remove column name
     1000                if (i == 0 && column.getValue().equals("Id"))
     1001                {
     1002                    column.setValue("");
     1003                }
     1004                tmpTable.add(column);
     1005                log
     1006                .debug("i = " + i + " templateColumnName = \"" + templateColumnName + "\" column \"" + column
     1007                .getValue() + "\" inserted.");
     1008            }
     1009            else
     1010            {
     1011                // Add new column for template column not in source table
     1012                Column column = new Column(templateColumnName);
     1013                // If initial Id column, remove column name
     1014                if (i == 0 && column.getValue().equals("Id"))
     1015                {
     1016                    column.setValue("");
     1017                }
     1018                tmpTable.add(column);
     1019                log
     1020                .debug("i = " + i + " templateColumnName = \"" + templateColumnName + "\" new column \"" + column
     1021                .getValue() + "\" inserted.");
     1022            }
     1023        }
     1024        // Return adapted source header.
     1025        return tmpTable.getHeader();
     1026    }
     1027   
     1028    /**
     1029        * Adapts a table row for source items so it fits in a table for template
     1030        * items. The tables for source and template items are used to find what
     1031        * cells in the source row are applicable in the template table. This is
     1032        * done by checking the names for each column. A column in the template
     1033        * table that has a corresponding column in the source table will have the
     1034        * source cell inserted, otherwise an empty cell. Columns unique to the
     1035        * source table will not trigger insertion of a cell.
     1036        *
     1037        * @param row Row Input row from source table to be adapted.
     1038        * @param startIndex int Index for first column to check
     1039        * @param templateTable Table Table for template items
     1040        * @param sourceTable Table Table for source items
     1041        * @return Row Output row for source item, modified to fit into template
     1042        *         table.
     1043    */
     1044    @SuppressWarnings("unchecked")
     1045    private Row adaptTableRow(Row row, int startIndex, Table templateTable,
     1046    Table sourceTable)
     1047    {
     1048        if (startIndex >= row.getCells().size())
     1049        {
     1050            // No cells to adapt, return input row.
     1051            return row;
     1052        }
     1053        /*
     1054            * Get hash table of column names and column indices in source table.
     1055        */
     1056        Hashtable<String, Integer> sourceColumnNameHashtable = new Hashtable<String, Integer>(
     1057        0);
     1058        for (int i = startIndex; i < sourceTable.getHeader().size(); i++)
     1059        {
     1060            Column srcc = sourceTable.getHeader().get(i);
     1061            String sourceColumnName = srcc.getValue();
     1062            if (sourceColumnName != null)
     1063            {
     1064                // Add source column name to hash table.
     1065                sourceColumnNameHashtable.put(sourceColumnName, new Integer(i));
     1066                log
     1067                .debug("i = " + i + " sourceColumnNameHashtable.get(" + sourceColumnName + ").intValue() = " + sourceColumnNameHashtable
     1068                .get(sourceColumnName).intValue());
     1069            }
     1070        }
     1071        /*
     1072            * For column startIndex and upwards, only keep source cells for columns
     1073            * existing in both source and template tables. Add empty cells for
     1074            * columns unique to template table.
     1075        */
     1076        ArrayList<Cell<?>> cellList = new ArrayList<Cell<?>>(0);
     1077        // Add cells up to startIndex.
     1078        for (int i = 0; i < startIndex; i++)
     1079        {
     1080            Cell<?> cell = row.getCells().get(i);
     1081            cellList.add(cell);
     1082            log
     1083            .debug("New row i = " + i + " cell value \"" + cell.getValue() + "\" copied.");
     1084        }
     1085        /*
     1086            * For column startIndex and upwards, add empty cells if necessary.
     1087        */
     1088        Cell emptyCell = new Cell<String>(null);
     1089        for (int i = startIndex; i < templateTable.getHeader().size(); i++)
     1090        {
     1091            Column c = templateTable.getHeader().get(i);
     1092            // Only add visible columns in template table
     1093            if (!c.isVisible())
     1094            {
     1095                continue;
     1096            }
     1097            // Check if corresponding source table cell exists, if any.
     1098            String templateColumnName = c.getValue();
     1099            if (sourceColumnNameHashtable.containsKey(templateColumnName))
     1100            {
     1101                // Source table cell OK
     1102                int sourceCellIndex = sourceColumnNameHashtable.get(
     1103                templateColumnName).intValue();
     1104                Cell<?> cell = row.getCells().get(sourceCellIndex);
     1105                cellList.add(cell);
     1106                log
     1107                .debug("New row i = " + i + " templateColumnName = \"" + templateColumnName + "\" cell value \"" + cell
     1108                .getValue() + "\" inserted.");
     1109            }
     1110            else
     1111            {
     1112                // Add empty cell for template column not in source table
     1113                cellList.add(emptyCell);
     1114                log
     1115                .debug("New row i = " + i + " templateColumnName = \"" + templateColumnName + "\" empty cell inserted.");
     1116            }
     1117        }
     1118        // Construct adapted source row.
     1119        row.setCells(cellList);
     1120        return row;
     1121    }
     1122   
     1123    /**
     1124        * Convenience method for fetching the
     1125        * table update button clicked flag.
     1126        *
     1127        * @return boolean The table update button clicked flag.
     1128    */
     1129    private boolean fetchTableUpdateButtonClickedFlag()
     1130    {
     1131        // Get table update button clicked flag
     1132        boolean tableUpdateButtonClicked = false;
     1133        Boolean tableUpdateButtonClickedFlagFromRequest = false;
     1134        try
     1135        {
     1136            tableUpdateButtonClickedFlagFromRequest = getValidBoolean(VTABLEUPDATEBUTTONCLICKED);
     1137            if (tableUpdateButtonClickedFlagFromRequest == null)
     1138            {
     1139                tableUpdateButtonClicked = false;
     1140            }
     1141            else
     1142            {
     1143                tableUpdateButtonClicked = tableUpdateButtonClickedFlagFromRequest;
     1144            }
     1145        }
     1146        catch (Exception e)
     1147        {
     1148            log.debug("Exception when trying to get valid parameter VTABLEUPDATEBUTTONCLICKED: " + e);
     1149        }
     1150        log.debug("tableUpdateButtonClickedFlagFromRequest = " + tableUpdateButtonClickedFlagFromRequest + " tableUpdateButtonClicked = " + tableUpdateButtonClicked);
     1151        //
     1152        log.debug("tableUpdateButtonClicked = " + tableUpdateButtonClicked);
     1153        return tableUpdateButtonClicked;
     1154    }
    11651155}
  • trunk/client/servlet/src/org/proteios/action/project/UploadDemoFiles.java

    r3626 r3899  
    11/*
    2  $Id$
    3 
    4  Copyright (C) 2007 Fredrik Levander, Gregory Vincic, Olle Mansson
    5 
    6  Files are copyright by their respective authors. The contributions to
    7  files where copyright is not explicitly stated can be traced with the
    8  source code revision system.
    9 
    10  This file is part of Proteios.
    11  Available at http://www.proteios.org/
    12 
    13  Proteios-2.x is free software; you can redistribute it and/or
    14  modify it under the terms of the GNU General Public License
    15  as published by the Free Software Foundation; either version 2
    16  of the License, or (at your option) any later version.
    17 
    18  Proteios is distributed in the hope that it will be useful,
    19  but WITHOUT ANY WARRANTY; without even the implied warranty of
    20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    21  GNU General Public License for more details.
    22 
    23  You should have received a copy of the GNU General Public License
    24  along with this program; if not, write to the Free Software
    25  Foundation, Inc., 59 Temple Place - Suite 330,
    26  Boston, MA  02111-1307, USA.
    27  */
     2    $Id$
     3       
     4    Copyright (C) 2007 Fredrik Levander, Gregory Vincic, Olle Mansson
     5    Copyright (C) 2010 Gregory Vincic
     6       
     7    Files are copyright by their respective authors. The contributions to
     8    files where copyright is not explicitly stated can be traced with the
     9    source code revision system.
     10       
     11    This file is part of Proteios.
     12    Available at http://www.proteios.org/
     13       
     14    Proteios-2.x is free software; you can redistribute it and/or
     15    modify it under the terms of the GNU General Public License
     16    as published by the Free Software Foundation; either version 2
     17    of the License, or (at your option) any later version.
     18       
     19    Proteios is distributed in the hope that it will be useful,
     20    but WITHOUT ANY WARRANTY; without even the implied warranty of
     21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     22    GNU General Public License for more details.
     23       
     24    You should have received a copy of the GNU General Public License
     25    along with this program; if not, write to the Free Software
     26    Foundation, Inc., 59 Temple Place - Suite 330,
     27    Boston, MA  02111-1307, USA.
     28*/
    2829package org.proteios.action.project;
    2930
     31import java.net.MalformedURLException;
     32import java.net.URL;
     33import java.util.ArrayList;
     34import java.util.List;
     35import org.proteios.Context;
     36import org.proteios.ContextEnabled;
     37import org.proteios.FileContext;
    3038import org.proteios.action.ProteiosAction;
    3139import org.proteios.core.DbControl;
     
    3846import se.lu.thep.waf.ActionException;
    3947import se.lu.thep.waf.constraints.InvalidParameterValue;
    40 import java.net.MalformedURLException;
    41 import java.net.URL;
    4248
    4349/**
    44  * Uploads a set of files for demonstration purposes.
    45  *
    46  * @author gregory
    47  */
     50    Uploads a set of files for demonstration purposes.     
     51*/
    4852public class UploadDemoFiles
    49     extends ProteiosAction<UploadDemoFiles>
     53extends ProteiosAction<UploadDemoFiles>
     54implements ContextEnabled
    5055{
    51   private static final String root = "http://www.proteios.org/trac/downloads/demoProjectFiles/";
    52   private ItemFactory factory = null;
    53   private DbControl dc = null;
    54 
    55 
    56   @Override
    57   protected void runMe()
    58       throws ActionException, InvalidParameterValue
    59   {
    60     dc = newDbControl();
    61     Project project = isProjectActive(dc);
    62     factory = new ItemFactory(dc);
    63     /***********************************************************************
    64      * Upload some files
    65      */
    66     Directory projectDir = project.getProjectDirectory();
    67     // Project directories get the name of the project
    68     addRobotFiles(projectDir);
    69     addMascotFiles(projectDir);
    70     addPeakListFiles(projectDir);
    71     //
    72     setMessage("Demo files uploaded");
    73     dc.commit();
    74   }
    75 
    76 
    77   /**
    78    * @param dc
    79    * @param parentDir
    80    * @throws ActionException
    81    */
    82   private void addPeakListFiles(Directory parentDir)
    83       throws ActionException
    84   {
    85     Directory dir = factory.create(Directory.class);
    86     dir.setParent(parentDir);
    87     dir.setName("Peaklist files");
    88     dc.saveItem(dir);
    89     FileType fileType = factory.getById(FileType.class, SystemItems
    90       .getId(FileType.MZDATA));
    91     uploadFile(dir, "qtof_A2.xml", fileType);
    92     uploadFile(dir, "qtof_A3.xml", fileType);
    93   }
    94 
    95 
    96   /**
    97    * @param dc
    98    * @param parentDir
    99    * @throws ActionException
    100    */
    101   private void addMascotFiles(Directory parentDir)
    102       throws ActionException
    103   {
    104     ItemFactory factory = new ItemFactory(dc);
    105     Directory dir = factory.create(Directory.class);
    106     dir.setParent(parentDir);
    107     dir.setName("Mascot files");
    108     dc.saveItem(dir);
    109     FileType fileType = factory.getById(FileType.class, SystemItems
    110       .getId(FileType.MASCOT_XML));
    111     uploadFile(dir, "result1.xml", fileType);
    112     uploadFile(dir, "result2.xml", fileType);
    113   }
    114 
    115 
    116   /**
    117    * @param dc
    118    * @param parentDir
    119    * @throws ActionException
    120    */
    121   private void addRobotFiles(Directory parentDir)
    122       throws ActionException
    123   {
    124     ItemFactory factory = new ItemFactory(dc);
    125     Directory dir = factory.create(Directory.class);
    126     dir.setParent(parentDir);
    127     dir.setName("Robot result files");
    128     dc.saveItem(dir);
    129     FileType fileType = factory.getById(FileType.class, SystemItems
    130       .getId(FileType.SHW_RESULT));
    131     uploadFile(dir, "robotResult.xml", fileType);
    132   }
    133 
    134 
    135   private void uploadFile(Directory dir, String fileName, FileType type)
    136       throws ActionException
    137   {
    138     URL fileUrl = getFile(fileName);
    139     File file = factory.create(File.class);
    140     file.setDirectory(dir);
    141     file.setName(fileName);
    142     file.setDescription("Use external plate id 18115042KAISA4 to import");
    143     file.setFileType(type);
    144     try
    145     {
    146       dc.saveItem(file);
    147       file.upload(fileUrl.openStream(), false);
    148       dc.saveItem(file);
    149     }
    150     catch (Exception e)
    151     {
    152       throw new ActionException(e);
    153     }
    154   }
    155 
    156 
    157   private URL getFile(String fileName)
    158       throws ActionException
    159   {
    160     try
    161     {
    162       return new URL(root + fileName);
    163     }
    164     catch (MalformedURLException e)
    165     {
    166       throw new ActionException(e);
    167     }
    168   }
     56    private static final String root = "http://www.proteios.org/trac/downloads/demoProjectFiles/";
     57    private ItemFactory factory = null;
     58    private DbControl dc = null;
     59       
     60    @Override
     61    protected void runMe() throws ActionException, InvalidParameterValue
     62    {
     63        dc = newDbControl();
     64        Project project = isProjectActive(dc);
     65        Directory projectDir = project.getProjectDirectory();
     66        factory = getItemFactory(dc);
     67        // Project directories get the name of the project
     68        addRobotFiles(projectDir);
     69        addMascotFiles(projectDir);
     70        addPeakListFiles(projectDir);
     71       
     72        setMessage("Demo files uploaded");
     73        dc.commit();
     74    }
     75       
     76    private void addPeakListFiles(Directory parentDir) throws ActionException
     77    {
     78        Directory dir = factory.create(Directory.class);
     79        dir.setParent(parentDir);
     80        dir.setName("Peaklist files");
     81        dc.saveItem(dir);
     82        FileType fileType = factory.getById(FileType.class, SystemItems
     83        .getId(FileType.MZDATA));
     84        uploadFile(dir, "qtof_A2.xml", fileType);
     85        uploadFile(dir, "qtof_A3.xml", fileType);
     86    }
     87       
     88    private void addMascotFiles(Directory parentDir) throws ActionException
     89    {
     90        Directory dir = factory.create(Directory.class);
     91        dir.setParent(parentDir);
     92        dir.setName("Mascot files");
     93        dc.saveItem(dir);
     94        FileType fileType = factory.getById(FileType.class, SystemItems
     95        .getId(FileType.MASCOT_XML));
     96        uploadFile(dir, "result1.xml", fileType);
     97        uploadFile(dir, "result2.xml", fileType);
     98    }
     99       
     100    private void addRobotFiles(Directory parentDir) throws ActionException
     101    {
     102        Directory dir = factory.create(Directory.class);
     103        dir.setParent(parentDir);
     104        dir.setName("Robot result files");
     105        dc.saveItem(dir);
     106        FileType fileType = factory.getById(FileType.class, SystemItems
     107        .getId(FileType.SHW_RESULT));
     108        uploadFile(dir, "robotResult.xml", fileType);
     109    }
     110       
     111    private void uploadFile(Directory dir, String fileName, FileType type) throws ActionException
     112    {
     113        URL fileUrl = getFile(fileName);
     114        File file = factory.create(File.class);
     115        file.setDirectory(dir);
     116        file.setName(fileName);
     117        file.setDescription("Use external plate id 18115042KAISA4 to import");
     118        file.setFileType(type);
     119        try
     120        {
     121            dc.saveItem(file);
     122            file.upload(fileUrl.openStream(), false);
     123            dc.saveItem(file);
     124        }
     125        catch (Exception e)
     126        {
     127            throw new ActionException(e);
     128        }
     129    }
     130       
     131    private URL getFile(String fileName) throws ActionException
     132    {
     133        try
     134        {
     135            return new URL(root + fileName);
     136        }
     137        catch (MalformedURLException e)
     138        {
     139            throw new ActionException(e);
     140        }
     141    }
     142   
     143    public List<Context> listContexts()
     144    {
     145        List<Context> contexts = new ArrayList<Context>(1);
     146        /*
     147            We want our action to appear as an extension when viewing files. Do
     148            this by adding a FileContext to the list of contexts.
     149        */
     150        FileContext files = new FileContext("UploadDemoFiles",
     151        "Upload demo files",
     152        UploadDemoFiles.class);
     153        contexts.add(files);
     154        return contexts;
     155    }   
    169156}
Note: See TracChangeset for help on using the changeset viewer.