chxavfileui.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:35k
源码类别:

Symbian

开发平台:

Visual C++

  1. /************************************************************************
  2.  * chxavfileui.h
  3.  * -------------
  4.  *
  5.  * Synopsis:
  6.  * Description: 
  7.  *
  8.  * encapsulates UI logic for file/folder renaming, deleting,Target:
  9.  * moving, etc.Symbian OS
  10.  *
  11.  * uses CHXAvFileStore to do actual operations
  12.  *
  13.  * (c) 1995-2003 RealNetworks, Inc. Patents pending. All rights reserved.
  14.  *
  15.  ************************************************************************/
  16. // Symbian includes...
  17. #include <coeutils.h>
  18. #include <aknlists.h>
  19. #include <aknutils.h>
  20. #include <barsread.h> 
  21. // Helix includes...
  22. #include "hxassert.h"
  23. // Include from this project...
  24. #include "chxavplayerui.h"
  25. #include "chxavdirectoryreader.h"
  26. #include "chxavcleanstring.h"
  27. #include "chxavcleanupstack.h"
  28. #include "chxavfilestore.h"
  29. #include "chxavmessagedialog.h"
  30. #include "realplayer.rsg"
  31. #include "realplayer.hrh"
  32. #include "chxavmisc.h"
  33. #include "hxsym_debug.h"
  34. #include "chxavfolderpopuplist.h"
  35. #include "chxavpathselector.h"
  36. #include "chxavfileui.h"
  37. namespace
  38. {
  39. //const TUint k_msActionNoteDelay = 1000;
  40. inline
  41. bool IsNonCancelError(TInt err)
  42. {
  43.     return  err != KErrNone && err != KErrCancel;
  44. }
  45. } // local
  46. CHXAvFileUI::CHXAvFileUI(bool bHideExtensions)
  47. : CHXAvNameDisplayTrait(bHideExtensions)
  48. , m_pCone(CCoeEnv::Static())
  49. , m_playerUI(0)
  50. , m_bIsCancelOpPending(false)
  51. {
  52. }
  53. CHXAvFileUI::~CHXAvFileUI()
  54. {
  55. }
  56. void CHXAvFileUI::EnableWaitNoteCancelButtonL(bool bEnable)
  57. {
  58.     if( bEnable )
  59.     {
  60.         const CHXAvCommand& userCancelCmd =
  61.             MakeCommand(this, &CHXAvFileUI::UserCancelPendingFileOp);
  62.         m_spWaitNote->SetCancelCommandL(userCancelCmd);
  63.     }
  64.     else
  65.     {
  66.         m_spWaitNote->ClearCancelCommand();
  67.     }
  68. }
  69. ////////////////////////////////////////////////////////////
  70. //
  71. void CHXAvFileUI::ConstructL(CHXAvPlayerUI* playerUI, const CHXAvFileStorePtr& spStore)
  72. {
  73.     HX_ASSERT(playerUI != 0);
  74.     HX_ASSERT(spStore);
  75.     m_playerUI = playerUI;
  76.     m_spStore = spStore;
  77.     m_spStore->SetObserver(this);
  78.     m_spWaitNote = new (ELeave) CHXAvWaitNote();
  79.     m_spLastUniqueName = KNullDesC().AllocL();
  80. }
  81. ////////////////////////////////////////////////////
  82. // get folder name from user and create it under current path
  83. //
  84. // KErrNone if created
  85. // KErrCancel if user cancels
  86. //
  87. TInt CHXAvFileUI::DoNewFolderL(TInt resIdPrompt)
  88. {
  89.     CHXAvCleanString defFolderName(R_DEFAULT_NEW_FOLDER_NAME);
  90.     const TUint flags = fSuggestUniqueDefaultName | fWantFolder;
  91.     QueryTargetNameResult res = QueryTargetNameL(CHXAvCleanString(resIdPrompt)(), 
  92.         m_spStore->GetCurrentPath(), defFolderName(), flags);
  93.     TInt err = KErrGeneral;
  94.     switch (res)
  95.     {
  96.         case qtrUnique:
  97.         case qtrOverwrite:
  98.             // got name...
  99.             DPRINTF(SYMP_FILE_UI, ("AvFileUI::DoNewFolderL(): creating '%s'n", dbg::CharPtr(m_nameBuf)()));
  100.     err = m_spStore->CreateChildFolderL(m_nameBuf, res == qtrOverwrite);
  101.             break;
  102.         case qtrAbort:
  103.     // user canceled
  104.     err = KErrCancel;
  105.             break;
  106.         default:
  107.             err = KErrGeneral;
  108.             break;
  109.     }
  110.     if( IsNonCancelError(err) )
  111.     {
  112.         HandleDiskFullCase(err);
  113.         CHXAvMessageDialog::DoAlertErrorL(CHXAvCleanString(R_ERR_CREATE_FOLDER_FAILED)());
  114.     }
  115.     return err;
  116. }
  117. ////////////////////////////////////////////////////////////
  118. // save playlist
  119. TInt CHXAvFileUI::DoSavePlaylistL(const TDesC& fullPathSource, const TDesC& targetName)
  120. {
  121.     const CopyFileResourceIds k_savePlaylistIds =
  122.     {
  123.         R_PROMPT_ENTER_SAVE_NAME, 
  124.         R_PROMPT_SAVE_TO, 
  125.         R_AVP_SAVE_BUTTON_TEXT,
  126.         R_NOW_SAVING_ITEM_FORMAT,
  127.         R_INFO_PLAYLIST_SAVED,   
  128.         R_ERR_SAVE_PLAYLIST_FAILED
  129.     };
  130.     return DoCopyFileL(fullPathSource, k_savePlaylistIds, targetName);
  131.     
  132. }
  133. ////////////////////////////////////////////////////////////
  134. // save clip
  135. TInt CHXAvFileUI::DoSaveClipL(const TDesC& fullPathSource, const TDesC& targetName)
  136. {
  137.     static const CopyFileResourceIds k_saveClipIds =
  138.     {
  139.         R_PROMPT_ENTER_SAVE_NAME,
  140.         R_PROMPT_SAVE_TO, 
  141.         R_AVP_SAVE_BUTTON_TEXT,
  142.         R_NOW_SAVING_ITEM_FORMAT,
  143.         R_INFO_CLIP_SAVED,  
  144.         R_ERR_SAVE_CLIP_FAILED
  145.     };
  146.     return DoCopyFileL(fullPathSource, k_saveClipIds, targetName);
  147. }
  148. ////////////////////////////////////////////////////////////
  149. // prompt user for target folder, than do copy file to that
  150. // folder
  151. TInt CHXAvFileUI::DoCopyFileL(const TDesC& fullPathSource, 
  152.                            const CopyFileResourceIds& resIds,
  153.                            const TDesC& targetName)
  154. {
  155.     TInt err = KErrCancel;
  156.     bool bGotIt = DoGetTargetFolderPathL(resIds.idPromptTargetPath, 
  157.                                         resIds.idPromptTargetPathSelectButtonText);
  158.     if(bGotIt)
  159.     {
  160. err = DoCopyFileL(m_targetFolderPath, fullPathSource, resIds, targetName);
  161.     }
  162.     return err;
  163. }
  164. ////////////////////////////////////////////////////////////
  165. // helper: called from DoCopyFileL()
  166. TInt CHXAvFileUI::DoCopyFileHelperL(const TDesC& pathDest, 
  167.     const TDesC& fullPathSource,
  168.             const CopyFileResourceIds& resIds,bool bAllowOverwrite)
  169. {
  170.     CHXAvCleanString msg(resIds.idInfoNowCopying, m_nameBuf);
  171.     m_spWaitNote->SetTextL(msg());
  172. #if defined(ASYNC_COPYMOVE)
  173.     EnableWaitNoteCancelButtonL(true);
  174. #endif
  175.     m_spWaitNote->StartAndKickL();
  176.     
  177.     TInt err = m_spStore->CopyFileL(pathDest, m_nameBuf, fullPathSource, bAllowOverwrite);
  178.     // handle case where file is opened read-only with fopen
  179.     if( err == KErrInUse )
  180.     {
  181.         DPRINTF(SYMP_FILE_UI, ("AvFileUI::DoCopyFileHelperL(): file is locked; doing locked file copyn"));
  182.         err = m_spStore->CopyFileAlternateL(pathDest, m_nameBuf, fullPathSource, bAllowOverwrite);
  183.     }
  184.     m_spWaitNote->EndL();
  185.     return err;
  186. }
  187. ////////////////////////////////////////////////////////////
  188. // prompt user for target name within target folder,
  189. // then copy the source
  190. //
  191. // pathDest     - folder path; absolute or relative to current root
  192. //
  193. // pathSource   - Full absolute path
  194. //
  195. TInt CHXAvFileUI::DoCopyFileL(const TDesC& pathDest, 
  196. const TDesC& fullPathSource,
  197.                                 const CopyFileResourceIds& resIds, 
  198.                                 const TDesC& targetName)                        
  199. {
  200.     DPRINTF(SYMP_FILE_UI, ("AvFileUI::DoCopyFileL(): '%s' -> '%s'n", dbg::CharPtr(fullPathSource)(), dbg::CharPtr(pathDest)()));
  201.     TInt err = KErrCancel;
  202.     // determine target filename
  203.     TPtrC ptrName(targetName);
  204.     if(ptrName.Length() == 0)
  205.     {
  206.         // no default name provide; use name of source file
  207.         ptrName.Set(CHXAvFile::GetNakedPathNode(fullPathSource));
  208.     }
  209.    
  210.     // get a unique name within destination folder
  211.     QueryTargetNameResult res = QueryTargetNameL(CHXAvCleanString(resIds.idPromptTargetName)(), pathDest,
  212.                                     ptrName, fSuggestUniqueDefaultName);
  213.     switch (res)
  214.     {
  215.         case qtrUnique:
  216.         case qtrOverwrite:
  217.             // got name...
  218.             err = DoCopyFileHelperL(pathDest, fullPathSource, resIds, (res == qtrOverwrite));
  219.             // display confirmation after successful copy
  220.             if( err == KErrNone )
  221.             {
  222.                 CHXAvMessageDialog::DoAlertConfirmL(CHXAvCleanString(resIds.idInfoConfirmCopy)());
  223.             }
  224.             break;
  225.         case qtrAbort:
  226.     // user canceled
  227.     err = KErrCancel;
  228.             break;
  229.         default:
  230.             err = KErrGeneral;
  231.             break;
  232.     }
  233.     if( IsNonCancelError(err) )
  234.     {
  235.         HandleDiskFullCase(err);
  236.         CHXAvMessageDialog::DoAlertErrorL(CHXAvCleanString(resIds.idInfoCopyFailed)());
  237.     }
  238.     return err;
  239. }
  240. #if(0)
  241. ////////////////////////////////////////////////////////////
  242. // prompt user for folder, then move item to it
  243. TInt CHXAvFileUI::DoCopyItemL(TInt idxItem, 
  244. TInt resIdPrompt)
  245. {
  246.     TInt err = KErrCancel;
  247.     // guard against index becoming invalid (by refresh) while waiting for user input
  248.     SUSPEND_REFRESH(m_spStore);
  249.     bool bGotIt = DoGetTargetFolderPathL(resIdPrompt, R_AVP_COPY_BUTTON_TEXT);
  250.     if(bGotIt)
  251.     {
  252. err = DoCopyItemL(m_targetFolderPath, idxItem);
  253.     }
  254.     return err;
  255. }
  256. #endif
  257. ////////////////////////////////////////////////////////////
  258. // prompt user for folder, then move item to it
  259. TInt CHXAvFileUI::DoMoveItemL(TInt idxItem, 
  260. TInt resIdPrompt)
  261. {
  262.     TInt err = KErrCancel;
  263.     SUSPEND_REFRESH(m_spStore);
  264.     bool bGotIt = DoGetTargetFolderPathL(resIdPrompt, R_AVP_MOVE_BUTTON_TEXT);
  265.     if(bGotIt)
  266.     {
  267. err = DoMoveItemL(m_targetFolderPath, idxItem);
  268.     }
  269.     return err;
  270. }
  271. ////////////////////////////////////////////////////////////
  272. // prompt user for folder, then move multiple items to it
  273. TInt CHXAvFileUI::DoMoveItemsL(const CArrayFix<TInt>& items, 
  274. TInt resIdPrompt)
  275. {
  276.     TInt err = KErrCancel;
  277.     SUSPEND_REFRESH(m_spStore);
  278.     bool bGotIt = DoGetTargetFolderPathL(resIdPrompt, R_AVP_MOVE_BUTTON_TEXT);
  279.     if(bGotIt)
  280.     {
  281. err = DoMoveItemsL(m_targetFolderPath, items);
  282.     }
  283.     return err;
  284. }
  285. ////////////////////////////////////////////////////////////
  286. // helper
  287. TPtrC CHXAvFileUI::NameFromIndex(TInt idxItem)
  288. {
  289.     const CHXAvFileStore::Entries& entries = m_spStore->GetEntries();
  290.     const TEntry& entry = entries[idxItem].m_entry;
  291.     NameExt pair = GetDisplayText(entry.iName, entry.IsDir());
  292.     return pair.first;
  293. }
  294. #if(0)
  295. ////////////////////////////////////////////////////////////
  296. // move single item to specified folder path
  297. //
  298. // return error if error other than user cancel occurs
  299. //
  300. // pathDest     -   absolute or relative to current root
  301. //
  302. TInt CHXAvFileUI::DoCopyItemL(const TDesC& pathDest, 
  303. TInt idxItem)
  304. {
  305.     DPRINTF(SYMP_FILE_UI, ("AvFileUI::DoCopyItemL(): copying idx %d to '%s'n", idxItem, dbg::CharPtr(pathDest)()));
  306.     SUSPEND_REFRESH(m_spStore);
  307.     CHXAvCleanString msg(R_NOW_COPYING_ITEM_FORMAT, NameFromIndex(idxItem));
  308.     m_spWaitNote->SetTextL(msg());
  309.     m_spWaitNote->StartAndKickL();
  310.     // move one item
  311.     TInt err = CopyItemHelperL(pathDest, idxItem);
  312.     m_spWaitNote->EndL();
  313.     if( IsNonCancelError(err) )
  314.     {
  315.         CHXAvMessageDialog::DoAlertErrorL(CHXAvCleanString(R_ERR_COPY_FAILED)());
  316.     }
  317.     return err;
  318. }
  319. #endif
  320. ////////////////////////////////////////////////////////////
  321. // move single item to specified folder path
  322. //
  323. // return error if error other than user cancel occurs
  324. //
  325. // pathDest     -   absolute or relative to current root
  326. //
  327. TInt CHXAvFileUI::DoMoveItemL(const TDesC& pathDest, 
  328. TInt idxItem)
  329. {
  330.     DPRINTF(SYMP_FILE_UI, ("AvFileUI::DoMoveItemL(): moving idx %d to '%s'n", idxItem, dbg::CharPtr(pathDest)()));
  331.     SUSPEND_REFRESH(m_spStore);
  332.     CHXAvCleanString msg(R_NOW_MOVING_ITEM_FORMAT, NameFromIndex(idxItem));
  333.     m_spWaitNote->SetTextL(msg());
  334.     m_spWaitNote->StartAndKickL();
  335.     // move one item
  336.     TInt err = MoveItemHelperL(pathDest, idxItem);
  337.     m_spWaitNote->EndL();
  338.     if( IsNonCancelError(err) )
  339.     {
  340.         CHXAvMessageDialog::DoAlertErrorL(CHXAvCleanString(R_ERR_MOVE_FAILED)());
  341.     }
  342.     return err;
  343. }
  344. ////////////////////////////////////////////////////////////
  345. // move multipe items to specified folder path
  346. //
  347. // return error if error other than user cancel occurs
  348. //
  349. // pathDest     -   absolute or relative to current root
  350. //
  351. TInt CHXAvFileUI::DoMoveItemsL(const TDesC& pathDest, 
  352.        const CArrayFix<TInt>& items)
  353. {
  354.     TInt err = KErrNone;
  355.     SUSPEND_REFRESH(m_spStore);
  356.     DPRINTF(SYMP_FILE_UI, ("AvFileUI::DoMoveItemsL(): moving %d items to '%s'n", items.Count(), dbg::CharPtr(pathDest)()));
  357.     m_spWaitNote->SetTextL(CHXAvCleanString(R_NOW_MOVING_MULT_ITEMS_FORMAT, items.Count())());
  358. #if defined(ASYNC_COPYMOVE)
  359.     EnableWaitNoteCancelButtonL(true);
  360. #endif
  361.     m_spWaitNote->StartAndKickL();
  362.     for( TInt idx = 0; idx < items.Count(); ++idx )
  363.     {
  364. err = MoveItemHelperL(pathDest, items[idx]);
  365. if( IsNonCancelError(err) )
  366. {
  367.             // XXXLCM offer continue, cancel choice?
  368.             DPRINTF(SYMP_FILE_UI, ("AvFileUI::DoMoveItemsL(): move failed (err = %ld)n", err));
  369.             break;
  370.         }
  371.     }
  372.     m_spWaitNote->EndL();
  373.     if( IsNonCancelError(err) )
  374.     {
  375.         CHXAvMessageDialog::DoAlertErrorL(CHXAvCleanString(R_ERR_MOVE_FAILED)());    
  376.     }
  377.     return err;
  378. }
  379. ////////////////////////////////////////////////////////////
  380. // pathDest fully qualified path (with drive letter), or relative to epStore root
  381. //
  382. TFileName* CHXAvFileUI::AllocSuggestedFileNameL(const TDesC& pathDest, const TDesC& defaultName, TUint flags )
  383. {
  384.     TFileName* pName = 0;
  385.     if( flags & fSuggestUniqueDefaultName )
  386.     {
  387.         // AllocUniqueDefaultNameL() needs full path...
  388.         TFileName* pFullPathDest = m_spStore->AllocFullPathL(pathDest, KNullDesC, CHXAvFile::ntFolder);
  389.         AUTO_PUSH_POP_DEL(pFullPathDest);
  390.         // pick a default file/folder name; we get full path ('c:realnetworksrootfoo.rm')
  391.         pName = CHXAvFile::AllocUniqueDefaultNameL(*pFullPathDest, defaultName, flags & fWantFolder, *this);
  392.         if(!pName)
  393.         {
  394.             // rare case; display no default name
  395.             DPRINTF(SYMP_FILE_UI, ("AvFileUI::AllocSuggestedFileNameL(): could not find unique name"));
  396.             pName = CHXAvFile::AllocFileNameL(KNullDesC); 
  397.         }
  398.     }
  399.     else
  400.     {
  401.         // we don't know/care whether this name would be unique within the destination path
  402.         pName = CHXAvFile::AllocFileNameL(defaultName);
  403.     }
  404.     return pName;
  405. }
  406. ////////////////////////////////////////////////////////////
  407. // get a unique, valid file or folder name from the
  408. // user
  409. //
  410. // args:
  411. //
  412. //   pathDest                 -  absolute or relative to current root
  413. //
  414. //   defaultName              -  filename to use for initializing text in dialog edit box
  415. //                            -  also provides default extension;
  416. //                            -  for folders, trailing '' is optional (handled)
  417. //
  418. // returns :
  419. //
  420. //   m_nameBuf is set as "name" or "name/" (depending on bWantFolder)
  421. //
  422. //   return false if user cancels
  423. //
  424. // notes:
  425. //
  426. //   if extensions are hidden, they are automatically added to what user enters
  427. //
  428. //   defaultName    prompt      user entry      result
  429. //
  430. //   cat            cat         dog.rm          dog.rm
  431. //   cat            cat         poop            poop
  432. //   cat.rm         cat         flee            flee.rm
  433. //   cat.rm         cat         cat.rm          cat.rm.rm
  434. //   .rm                        bob             bob.rm
  435. //                              bob             bob
  436. //
  437. //   same examples, if extensions are not hidden:
  438. //
  439. //   cat            cat         dog.rm          dog.rm
  440. //   cat            cat         poop            poop
  441. //   cat.rm         cat.rm      flee            flee
  442. //   cat.rm         cat.rm      cat             cat.rm
  443. //   .rm            .rm         bob             bob
  444. //                              bob             bob
  445. //
  446. CHXAvFileUI::QueryTargetNameResult 
  447. CHXAvFileUI::QueryTargetNameL(const TDesC& prompt,const TDesC& pathDest,
  448. const TDesC& defaultName, TUint flags)                      
  449. {
  450.     DPRINTF(SYMP_FILE_UI, ("AvFileUI::QueryTargetNameL(): in folder '%s'n", dbg::CharPtr(pathDest)()));
  451.     QueryTargetNameResult res = qtrAbort;
  452.     // reset working buffer
  453.     m_nameBuf.SetLength(0);
  454.     //
  455.     // determine how many chars are left for new filename within given path; we'll
  456.     // restrict user input so we don't overflow filename buffer
  457.     //
  458.     TFileName* pFullPathDest = m_spStore->AllocFullPathL(pathDest, KNullDesC, CHXAvFile::ntFolder);
  459.     AUTO_PUSH_POP_DEL(pFullPathDest);
  460.     TInt cchMaxName = KMaxFileName - pFullPathDest->Length();
  461.     // possibly subtract length of hidden extension or folder suffix
  462.     NameExt ext = GetDisplayText(defaultName, flags & fWantFolder);
  463.     cchMaxName -= ext.second.Length();
  464.     DPRINTF(SYMP_FILE_UI, ("AvFileUI::QueryTargetNameL(): max chars left for name = %dn", cchMaxName));
  465.     if( cchMaxName <= 0 )
  466.     {
  467.         // destination path is too long!
  468.         return qtrPathTooLong;
  469.     } 
  470.     
  471.     // ui spec requires that we arbitrarily limit names to 40 chars; code does not care
  472.     if (cchMaxName > CHXAvMisc::KAVPMaxNakedFileName )
  473.     {
  474.         cchMaxName = CHXAvMisc::KAVPMaxNakedFileName;
  475.     }
  476.     InitNameBufWithSuggestionL(pathDest, defaultName, flags);
  477.     
  478.     for( bool bNeedToPrompt = true; bNeedToPrompt ; )
  479.     {
  480. //
  481.         // name buf should have something like 'foo.rm'; now possibly split name into
  482.         // user-display version ('foo') and ext ('.rm')
  483.         //
  484.         HBufC* pbuffNameInfo = m_nameBuf.AllocL(); // nameInfo will refer into this buffer
  485.         AUTO_PUSH_POP_DEL(pbuffNameInfo);
  486.         NameExt nameInfo = GetDisplayText(*pbuffNameInfo, flags & fWantFolder);
  487.         TFileName* pName = CHXAvMessageDialog::GetFileNameFromUserL(prompt, nameInfo.first, cchMaxName);
  488. if( pName )
  489. {
  490.             // update name buf, re-adding extension that we might have lopped off for display purposes
  491.     m_nameBuf.Copy(*pName);
  492.     HX_DELETE(pName);
  493.     m_nameBuf.Append(nameInfo.second);
  494.             // assume we'll be able to use this name for now...
  495.             bNeedToPrompt = false;
  496.             DPRINTF(SYMP_FILE_UI, ("FileUi::QueryTargetNameL(): name requested = '%s'n", dbg::CharPtr(m_nameBuf)()));
  497.             // check for existence of file or folder having same name
  498.     bool bFileNameExists = m_spStore->PathExistsL(pathDest, m_nameBuf, CHXAvFile::ntFile);
  499.             bool bFolderNameExists =  m_spStore->PathExistsL(pathDest, m_nameBuf, CHXAvFile::ntFolder);
  500.             if( bFolderNameExists )
  501.             {
  502.                 DPRINTF(SYMP_FILE_UI, ("FileUi::QueryTargetNameL(): folder matching name already existsn"));
  503.                 // overwrite of folder (or creation of file having same name as existing folder) never allowed
  504.                 CHXAvMessageDialog::DoAlertInfoL(CHXAvCleanString(R_ERR_NAME_ALREADY_EXISTS)());
  505.                 bNeedToPrompt = true;
  506.             }
  507.             else if(flags & fWantFolder)
  508.             {
  509.                 // looking for folder target
  510.                 if( bFileNameExists )
  511.                 {
  512.                     // overwrite of file (or creeating of folder having same name as existing file never allowed
  513.                     CHXAvMessageDialog::DoAlertInfoL(CHXAvCleanString(R_ERR_NAME_ALREADY_EXISTS)());
  514.                     bNeedToPrompt = true;
  515.                 }
  516.                 else
  517.                 {
  518.                     // user selected a unique folder name (path already checked above)
  519.                     res = qtrUnique;
  520.                 }
  521.             }
  522.             else
  523.             {
  524.                 // looking for file target
  525.                 if( bFileNameExists )
  526.                 {
  527.                     if( flags & fDisallowFileOverwrite )
  528.                     {
  529.                         // overwrite of file not allowed
  530.                         CHXAvMessageDialog::DoAlertInfoL(CHXAvCleanString(R_ERR_NAME_ALREADY_EXISTS)());
  531.                         bNeedToPrompt = true;
  532.                     }
  533.                     else
  534.                     {
  535.                         // ask user if we should overwrite selected filename
  536.                         NameExt newNameInfo = GetDisplayText(m_nameBuf, flags & fWantFolder);
  537.                         DPRINTF(SYMP_FILE_UI, ("FileUi::QueryTargetNameL(): file matching name already existsn"));
  538.               
  539.                         bNeedToPrompt = !CHXAvMessageDialog::DoQueryL(CHXAvCleanString(R_CONF_OVERWRITE_ITEM_FORMAT, newNameInfo.first)());
  540.                         if( !bNeedToPrompt) 
  541.                         {
  542.                             // user opted to overwrite existing file
  543.                             res = qtrOverwrite;
  544.                         }
  545.                     }
  546.                 }
  547.                 else
  548.                 {
  549.                     // user selected a unique folder name
  550.                     res = qtrUnique;
  551.                 }
  552.             }
  553.             if( bNeedToPrompt )
  554.             {
  555.                 // we will prompt again; ensure that we suggest a unique name from now on
  556.         InitNameBufWithSuggestionL(pathDest, m_nameBuf, flags | fSuggestUniqueDefaultName);
  557.             }
  558. }
  559. else
  560. {
  561.     // user canceled
  562.     m_nameBuf.Copy(KNullDesC);
  563.     bNeedToPrompt = false;
  564. }
  565.     }
  566.     // remember this...
  567.     m_spLastUniqueName = m_nameBuf.AllocL();
  568.     return res;
  569. }
  570. ////////////////////////////////////////////////////////
  571. // initialize name buffer with a default filename
  572. //
  573. // may or may not be slightly modified to ensure unique within
  574. // destination path (depends on flags)
  575. //
  576. void CHXAvFileUI::InitNameBufWithSuggestionL(const TDesC& pathDest, const TDesC& fileName, TUint flags)
  577. {
  578.     TFileName* pNameToSuggest = AllocSuggestedFileNameL(pathDest, fileName, flags);
  579.     AUTO_PUSH_POP_DEL(pNameToSuggest);
  580.     // work with leaf (filename) part of path ('foo.rm')
  581.     TPtrC ptrNode (CHXAvFile::GetNakedPathNode(*pNameToSuggest));
  582.     m_nameBuf.Copy(ptrNode);
  583. }
  584. ////////////////////////////////////////////////////////////
  585. // helper: called from MoveItemHelperL
  586. //
  587. // prompt for a name, then (if user gives good name) do the move
  588. //
  589. TInt CHXAvFileUI::DoPromptMoveItemHelperL(const TDesC& pathDest, TInt idxItem)
  590. {
  591.     SUSPEND_REFRESH(m_spStore);
  592.     const CHXAvFileStore::Entries& entries = m_spStore->GetEntries();
  593.     const TEntry& entry = entries[idxItem].m_entry;
  594.     TInt err = KErrGeneral;
  595.     TUint flags = fSuggestUniqueDefaultName;
  596.     if (entry.IsDir())
  597.     {
  598.         flags |= fWantFolder;
  599.     }
  600.     
  601.     // ask for a suitable filename for the target file
  602.     QueryTargetNameResult res = QueryTargetNameL(CHXAvCleanString(R_PROMPT_ENTER_NEW_NAME)(),
  603.     pathDest, 
  604.     entry.iName, flags);
  605.     switch (res)
  606.     {
  607.         case qtrUnique:
  608.         case qtrOverwrite:
  609.             // got target name...
  610.     err = m_spStore->MoveItemL(idxItem, pathDest, 
  611.     m_nameBuf, res == qtrOverwrite);
  612.             break;
  613.         case qtrAbort:
  614.     // user canceled
  615.     err = KErrCancel;
  616.             break;
  617.         default:
  618.             err = KErrGeneral;
  619.             break;
  620.     }
  621.     return err;
  622. }
  623. ////////////////////////////////////////////////////////////
  624. // helper: called from MoveItemHelperL
  625. //
  626. // confirm overwrite, then (if user accepts) do the move
  627. //
  628. TInt CHXAvFileUI::DoOverwriteMoveItemHelperL(const TDesC& pathDest, TInt idxItem)
  629. {
  630.     TInt err = KErrGeneral;
  631.     SUSPEND_REFRESH(m_spStore);
  632.     // check for move to self
  633.     if(m_spStore->IsSamePathL(pathDest, idxItem))
  634.     {
  635.         // do nothing; pretend user canceled (same effect as moving to self)
  636.         err = KErrCancel;
  637.     }
  638.     else 
  639.     {
  640.         //
  641.         // in case where move target path is a folder (and source is either file or folder) we
  642.         // force the user to create a unique name; other apps like Photo Album behave this
  643.         // way (there are some hassles with underlying API when specifying folder as move target,
  644.         // although there are work-arounds)
  645.         //
  646.         bool bFolderExists = m_spStore->NameExistsInTargetPathL(pathDest, idxItem, CHXAvFile::ntFolder);
  647.         if(bFolderExists)
  648.         {
  649.             CHXAvMessageDialog::DoAlertInfoL(CHXAvCleanString(R_ERR_NAME_ALREADY_EXISTS)());
  650.             // prompt for new target name
  651.             err = DoPromptMoveItemHelperL(pathDest, idxItem);
  652.         }
  653.         else
  654.         {
  655.             HX_ASSERT(m_spStore->NameExistsInTargetPathL(pathDest, idxItem, CHXAvFile::ntFile));
  656.             // file exists; confirm that delete is ok
  657.             TPtrC name = NameFromIndex(idxItem);
  658.     if(CHXAvMessageDialog::DoQueryL(CHXAvCleanString(R_CONF_OVERWRITE_ITEM_FORMAT, name)()) )
  659.     {
  660.                 // user opts to overwrite target...
  661.                 const CHXAvFileStore::Entries& entries = m_spStore->GetEntries();
  662.                 const TEntry& entry = entries[idxItem].m_entry;
  663.         err = m_spStore->MoveItemL(idxItem, pathDest, entry.iName, true /*overwrite*/);
  664.     }
  665.             else
  666.             {
  667.                 // user opted not to overwrite target; prompt for new target name
  668.                 err = DoPromptMoveItemHelperL(pathDest, idxItem);
  669.             }
  670.         }
  671.     }
  672.     return err;
  673. }
  674. ////////////////////////////////////////////////////////////
  675. // move a file from disk; if successful, delete the name from the
  676. // current list
  677. //
  678. // if successful, 'text items' are updated and 'remove indexes' contains
  679. // indexes of deleted items
  680. //
  681. // pathDest               - absolute or relative to current root
  682. //
  683. // idxItem                - index of item in current folder path
  684. //
  685. TInt CHXAvFileUI::MoveItemHelperL(const TDesC& pathDest, TInt idxItem)
  686. {
  687.     DPRINTF(SYMP_FILE_UI, ("AvFileUI::MoveItemHelperL(): moving item %d to '%s'n", idxItem, dbg::CharPtr(pathDest)()));
  688.     SUSPEND_REFRESH(m_spStore);
  689.     const CHXAvFileStore::Entries& entries = m_spStore->GetEntries();
  690.     HX_ASSERT(idxItem < entries.Nelements());
  691.     TInt err = KErrGeneral;
  692.     if( idxItem < entries.Nelements())
  693.     {
  694. HX_ASSERT(m_spStore->PathExistsL(pathDest, KNullDesC));
  695.  
  696.         if(!m_spStore->IsSafeFileNameLengthL(pathDest, idxItem))
  697.         {
  698.             // name can't fit in target path; prompt for safer (smaller) name
  699.             err = DoPromptMoveItemHelperL(pathDest, idxItem);
  700.         }
  701.         else if(m_spStore->NameExistsInTargetPathL(pathDest, idxItem))
  702. {
  703.             err = DoOverwriteMoveItemHelperL(pathDest, idxItem); 
  704. }
  705. else
  706. {
  707.             const TEntry& entry = entries[idxItem].m_entry;
  708.     // target doesn't exist; go ahead and move
  709.     err = m_spStore->MoveItemL(idxItem, pathDest, entry.iName, false /*rename*/);
  710. }
  711.     }
  712.     HandleDiskFullCase(err);
  713.     return err;
  714. }
  715. ////////////////////////////////////////////////////
  716. // prompt user to select a folder via a pop-up 
  717. // folder navigation list
  718. //
  719. // set folder name in working buffer if folder is selected
  720. //
  721. bool CHXAvFileUI::DoGetTargetFolderPathL(TInt resIdPrompt, TInt resIdSelectButton)
  722. {
  723.     m_targetFolderPath.Zero();
  724.     CHXAvPathSelector selector;
  725.     selector.InitL(m_playerUI->GetMediaStoreInfoL(), resIdPrompt, resIdSelectButton);
  726.     bool bSelected = selector.PromptUserSelectPathL();
  727.     if( bSelected )
  728.     {
  729.         m_targetFolderPath.Copy(selector.GetSelectedPath());
  730.     }
  731.     return bSelected;
  732.     
  733. }
  734. ////////////////////////////////////////////////////////////
  735. // delete selected item
  736. //
  737. // return KErrCancel if user cancels
  738. //
  739. TInt CHXAvFileUI::DoDeleteItemL(TInt idxItem)
  740. {
  741.     TInt err = KErrCancel;
  742.     SUSPEND_REFRESH(m_spStore);
  743.     const CHXAvFileStore::Entries& entries = m_spStore->GetEntries();
  744.     const TEntry& entry = entries[idxItem].m_entry;
  745.     bool bUserConfirmed = false;
  746.     if( entry.IsDir() )
  747.     {
  748.         bUserConfirmed = CHXAvMessageDialog::DoQueryL(R_CONF_DELETE_FOLDER);
  749.     }
  750.     else
  751.     {
  752.         TPtrC name = NameFromIndex(idxItem);
  753.         bUserConfirmed = CHXAvMessageDialog::DoQueryL(CHXAvCleanString(R_CONF_DELETE_ITEM_FORMAT, name)());
  754.     }
  755.     
  756.     if( bUserConfirmed )
  757.     {
  758.         CHXAvCleanString msg(R_NOW_DELETING_ITEM_FORMAT, NameFromIndex(idxItem));
  759.         //CHXAvCleanString msg(R_NOW_DELETING);
  760.         m_spWaitNote->SetTextL(msg());
  761.         //EnableWaitNoteCancelButtonL(true);
  762.         m_spWaitNote->StartAndKickL();
  763.         
  764.      err = m_spStore->DeleteItemL(idxItem);
  765.         m_spWaitNote->EndL();
  766. if(IsNonCancelError(err))
  767. {
  768.             CHXAvMessageDialog::DoAlertErrorL(CHXAvCleanString(R_ERR_DELETE_FAILED)());
  769. }
  770.     }
  771.     return err;
  772. }
  773. ////////////////////////////////////////////////////////////
  774. // delete multiple items (query just once)
  775. //
  776. // only files (not folder) may be deleted this way
  777. //
  778. // return KErrCancel if user cancels
  779. //
  780. TInt CHXAvFileUI::DoDeleteItemsL(const CArrayFix<TInt>& items)
  781. {
  782.     SUSPEND_REFRESH(m_spStore);
  783.     
  784.     TInt count = items.Count();
  785.     //
  786.     // confirm with user
  787.     //
  788.     bool bUserConfirmed = false;
  789.     if( 1 == count )
  790.     {
  791.         TPtrC name = NameFromIndex(items[0]);
  792.         bUserConfirmed = CHXAvMessageDialog::DoQueryL(CHXAvCleanString(R_CONF_DELETE_ITEM_FORMAT, name)());
  793.     }
  794.     else
  795.     {
  796.         bUserConfirmed = CHXAvMessageDialog::DoQueryL(CHXAvCleanString(R_CONF_DELETE_MULT_ITEMS_FORMAT, count)());
  797.     }
  798.     //
  799.     // do the deed if user said 'ok'
  800.     //
  801.     TInt err = KErrCancel;
  802.     if(bUserConfirmed)
  803.     {
  804.         
  805.         m_spWaitNote->SetTextL(CHXAvCleanString(R_NOW_DELETING_MULT_ITEMS_FORMAT, count)());
  806.         //EnableWaitNoteCancelButtonL(true);
  807.         m_spWaitNote->StartAndKickL();
  808. for( TInt idx = 0; idx < count; ++idx )
  809. {
  810.     TInt idxDeleteItem = items[idx];
  811.     HX_ASSERT(!m_spStore->GetEntries()[idxDeleteItem].m_entry.IsDir()); // folders can't be in multiple item list!
  812.     
  813.     err = m_spStore->DeleteItemL(idxDeleteItem);
  814.     if(IsNonCancelError(err))
  815.     {
  816. // XXXLCM ask to continue/cancel?
  817. break;
  818.     }
  819. }
  820.         m_spWaitNote->EndL();
  821.         if( IsNonCancelError(err) )
  822.         {
  823.             CHXAvMessageDialog::DoAlertErrorL(CHXAvCleanString(R_ERR_DELETE_FAILED)());    
  824.         }
  825.     }
  826.     return err;
  827. }
  828. ////////////////////////////////////////////////////
  829. // show error message if err indicates disk full
  830. void CHXAvFileUI::HandleDiskFullCase(TInt err)
  831. {
  832.     // display error message if copy failed due to low disk space
  833.     if( KErrDiskFull == err || KErrNoMemory == err)
  834.     {
  835.         CHXAvMessageDialog::DoSystemErrorNoteL(err);
  836.     }
  837. }
  838. ////////////////////////////////////////////////////
  839. // prompt user for a new name for the currently
  840. // hilighted file or folder
  841. //
  842. TInt CHXAvFileUI::DoRenameL(TInt idxItem, TInt resIdPrompt)
  843. {
  844.     DPRINTF(SYMP_FILE_UI, ("CHXAvFileUI::DoRenameL(): idx = n", idxItem));
  845.     SUSPEND_REFRESH(m_spStore);
  846.     const CHXAvFileStore::Entries& entries = m_spStore->GetEntries();
  847.     HX_ASSERT(idxItem < entries.Nelements());
  848.     const TEntry& entry = entries[idxItem].m_entry;
  849.     TInt err = KErrGeneral;
  850.     TUint flags = 0;
  851.     if(entry.IsDir())
  852.     {
  853.         flags |= fWantFolder;
  854.     }
  855.     // get new file name...
  856.     QueryTargetNameResult res = QueryTargetNameL(CHXAvCleanString(resIdPrompt)(), 
  857. m_spStore->GetCurrentPath(), 
  858. entry.iName, flags); 
  859.     switch (res)
  860.     {
  861.         case qtrUnique:
  862.         case qtrOverwrite:
  863.             // got name...
  864.     err = m_spStore->MoveItemL(idxItem, m_nameBuf, res == qtrOverwrite, true /*use rename*/);
  865.             break;
  866.         case qtrAbort:
  867.     // user canceled
  868.     err = KErrCancel;
  869.             break;
  870.         default:
  871.             err = KErrGeneral;
  872.             break;
  873.     }
  874.     if(IsNonCancelError(err))
  875.     {
  876.         HandleDiskFullCase(err);
  877.         CHXAvMessageDialog::DoAlertErrorL(CHXAvCleanString(R_ERR_RENAME_FAILED)());
  878.     }
  879.     DPRINTF(SYMP_FILE_UI, ("CHXAvFileUI::DoRenameL(): exitn"));
  880.     return err;
  881. }
  882. ////////////////////////////////////////
  883. // query folder name, then do save link
  884. // to that folder
  885. TInt
  886. CHXAvFileUI::DoCreateLinkL(const CHXString& url, const TDesC& defaultName)
  887. {
  888.     TInt err = KErrCancel;
  889.     bool bGotIt = DoGetTargetFolderPathL(R_PROMPT_SAVE_TO, R_AVP_SAVE_BUTTON_TEXT);
  890.     if(bGotIt)
  891.     {
  892. err = DoCreateLinkL(m_targetFolderPath, url, defaultName);
  893.     }
  894.     return err;
  895. }
  896. ////////////////////////////////////////
  897. // create a link file pointing to the given
  898. // URL in the given folder
  899. //
  900. // return KErrCancel if user cancels
  901. //
  902. TInt
  903. CHXAvFileUI::DoCreateLinkL(const TDesC& folder, 
  904.    const CHXString& url, 
  905.                            const TDesC& defaultName)
  906. {  
  907.     TInt err = KErrGeneral;
  908.     TFileName* pDefaultName = CHXAvFile::AllocFileNameL(defaultName);
  909.     AUTO_PUSH_POP_DEL(pDefaultName);
  910.     if( pDefaultName->Length() == 0 )
  911.     {
  912.         // no default name given...
  913.         CHXAvCleanString lastResortName(R_DEFAULT_NEW_LINK_NAME);
  914.         pDefaultName->Copy(lastResortName());
  915.     }
  916.     pDefaultName->Append(CHXAvUtil::KLinkFileExt);
  917.     // get a unique name within destination folder
  918.     QueryTargetNameResult res = QueryTargetNameL(CHXAvCleanString(R_PROMPT_ENTER_SAVE_NAME)(), 
  919. folder, *pDefaultName, fSuggestUniqueDefaultName);
  920.     // XXXLCM check for low disk?
  921.     switch (res)
  922.     {
  923.         case qtrUnique:
  924.         case qtrOverwrite:
  925.             // got name...
  926.             {
  927.         FILE* pFile = m_spStore->OpenFileL(folder, m_nameBuf, "wt");
  928.         if(pFile)
  929.         {
  930.             ::fprintf(pFile, "%sn", static_cast<const char*>(url));
  931.             ::fclose(pFile);
  932.                     err = KErrNone;
  933.                     CHXAvMessageDialog::DoAlertConfirmL(CHXAvCleanString(R_INFO_LINK_SAVED)());
  934.         }
  935.                 else
  936.                 {
  937.                     err = KErrGeneral;
  938.                 }
  939.             }
  940.             break;
  941.         case qtrAbort:
  942.     // user canceled
  943.     err = KErrCancel;
  944.             break;
  945.         default:
  946.             err = KErrGeneral;
  947.             break;
  948.     }
  949.     if( IsNonCancelError(err) )
  950.     {
  951.         HandleDiskFullCase(err);
  952.         CHXAvMessageDialog::DoAlertErrorL(CHXAvCleanString(R_ERR_CREATE_LINK_FAILED)());
  953.     }
  954.     return err;
  955. }
  956. void CHXAvFileUI::UserCancelPendingFileOp()
  957. {
  958.     DPRINTF(SYMP_FILE_UI, ("CHXAvFileUI::UserCancelPendingFileOp()n"));
  959.     m_bIsCancelOpPending = true;
  960. #if defined(ASYNC_COPYMOVE)
  961.     m_spStore->CancelAsyncFileOp();
  962. #endif
  963. }
  964. void CHXAvFileUI::OnFileOpStart(FileStoreOperationObserver::OperationType type, const TDesC& source, const TDesC& target)
  965. {
  966.     //DPRINTF(SYMP_FILE_UI, ("CHXAvFileUI::OnFileOpStart(): op = %d; src = '%s'; dst = '%s'n", type,  dbg::CharPtr(source)(), dbg::CharPtr(target)()));
  967.     m_bIsCancelOpPending = false;
  968. }
  969. bool CHXAvFileUI::OnFileOpTick(FileStoreOperationObserver::OperationType type, const TDesC& source, const TDesC& target, TInt64 cbCopied)
  970. {
  971.     //DPRINTF(SYMP_FILE_UI, ("CHXAvFileUI::OnFileOpTick(): op = %d; src = '%s'; dst = '%s'; cb = %lun", type,  dbg::CharPtr(source)(), dbg::CharPtr(target)(), cbCopied.Low()));
  972.     return !m_bIsCancelOpPending;
  973. }
  974. void CHXAvFileUI::OnFileOpEnd(FileStoreOperationObserver::OperationType type, TInt err, const TDesC& source, const TDesC& target)
  975. {
  976.     //DPRINTF(SYMP_FILE_UI, ("CHXAvFileUI::OnFileOpEnd(): op = %d; err = %d, src = '%s'; dst = '%s'n", type, err, dbg::CharPtr(source)(), dbg::CharPtr(target)()));
  977.     
  978.     m_bIsCancelOpPending = false;
  979. }