diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 16:58:10 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 16:58:10 +0200 |
commit | fefe20351d0720683990b666584b6879c90bd37d (patch) | |
tree | 8ab90520ae2123ac84293b0f9cec006317e5fc01 | |
parent | 1.18 (diff) | |
download | FreeFileSync-fefe20351d0720683990b666584b6879c90bd37d.tar.gz FreeFileSync-fefe20351d0720683990b666584b6879c90bd37d.tar.bz2 FreeFileSync-fefe20351d0720683990b666584b6879c90bd37d.zip |
1.19
54 files changed, 4034 insertions, 2182 deletions
diff --git a/Application.cpp b/Application.cpp index fee24b79..be358912 100644 --- a/Application.cpp +++ b/Application.cpp @@ -204,23 +204,27 @@ void Application::runBatchMode(const wxString& filename, xmlAccess::XmlGlobalSet else statusHandler = std::auto_ptr<BatchStatusHandler>(new BatchStatusHandlerGui(batchCfg.handleError, returnValue)); + //PREPARE FILTER + std::auto_ptr<FreeFileSync::FilterProcess> filterInstance(NULL); + if (batchCfg.mainCfg.filterIsActive) + filterInstance.reset(new FreeFileSync::FilterProcess(batchCfg.mainCfg.includeFilter, batchCfg.mainCfg.excludeFilter)); + //COMPARE DIRECTORIES FreeFileSync::FolderComparison folderCmp; FreeFileSync::CompareProcess comparison(globalSettings.shared.traverseDirectorySymlinks, globalSettings.shared.fileTimeTolerance, + globalSettings.shared.ignoreOneHourDiff, globalSettings.shared.warningDependentFolders, + filterInstance.get(), statusHandler.get()); comparison.startCompareProcess(batchCfg.directoryPairs, batchCfg.mainCfg.compareVar, + batchCfg.mainCfg.syncConfiguration, folderCmp); - //APPLY FILTERS - if (batchCfg.mainCfg.filterIsActive) - FreeFileSync::filterGridData(folderCmp, batchCfg.mainCfg.includeFilter, batchCfg.mainCfg.excludeFilter); - //check if there are files/folders to be sync'ed at all - if (!synchronizationNeeded(folderCmp, batchCfg.mainCfg.syncConfiguration)) + if (!synchronizationNeeded(folderCmp)) { statusHandler->addFinalInfo(_("Nothing to synchronize according to configuration!")); //inform about this special case return; @@ -233,9 +237,10 @@ void Application::runBatchMode(const wxString& filename, xmlAccess::XmlGlobalSet globalSettings.shared.traverseDirectorySymlinks, globalSettings.shared.warningSignificantDifference, globalSettings.shared.warningNotEnoughDiskSpace, + globalSettings.shared.warningUnresolvedConflicts, statusHandler.get()); - synchronization.startSynchronizationProcess(folderCmp, batchCfg.mainCfg.syncConfiguration); + synchronization.startSynchronizationProcess(folderCmp); } catch (FreeFileSync::AbortThisProcess&) //exit used by statusHandler { diff --git a/Changelog.txt b/Changelog.txt index 416071e3..7a513639 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,6 +1,26 @@ FreeFileSync ------------ +Changelog v1.19 +--------------- +New synchronization preview +Sync-direction can be adapted manually +New category type "conflict" +New check for unresolved conflicts +Improved overall GUI layout +New check for erroneous file modification dates +Optional popup to notify on changed configuration +Files with invalid dates (e.g. year 30.000) do not result in a program abort anymore +Replaced column "full name" by "full path" to be combined with "filename" +Apply filtering WHILE comparing (if activated) and avoid traversing excluded directories +New filter paradigm: use relative instead of absolute names +New option "ignore DST +/- 1-hour" to correctly handle daylight saving changes +Sync preview statistics now on main dialog +Show only relevant synchronization options +File icon display configurable via grid column context menu +Updated translation files + + Changelog v1.18 --------------- Linux build officially released: all major problems solved! diff --git a/FreeFileSync.cbp b/FreeFileSync.cbp index c3b5640f..42cb6edb 100644 --- a/FreeFileSync.cbp +++ b/FreeFileSync.cbp @@ -77,6 +77,7 @@ </Target> </Build> <Compiler> + <Add option="-Wredundant-decls" /> <Add option="-Wall" /> <Add option="-pipe" /> <Add option="-mthreads" /> @@ -105,11 +106,6 @@ <Add library="libws2_32.a" /> <Add directory="C:\Programme\C++\wxWidgets\lib\gcc_lib" /> </Linker> - <Unit filename="structures.cpp" /> - <Unit filename="structures.h"> - <Option target="Debug" /> - <Option target="Release" /> - </Unit> <Unit filename="WxWizFrame.fbp"> <Option target="Debug" /> <Option target="Release" /> @@ -228,6 +224,11 @@ <Option target="Debug" /> <Option target="Release" /> </Unit> + <Unit filename="structures.cpp" /> + <Unit filename="structures.h"> + <Option target="Debug" /> + <Option target="Release" /> + </Unit> <Unit filename="synchronization.cpp" /> <Unit filename="synchronization.h"> <Option target="Debug" /> diff --git a/Languages/chinese_simple.lng b/Languages/chinese_simple.lng index af963b6e..a72ffc60 100644 --- a/Languages/chinese_simple.lng +++ b/Languages/chinese_simple.lng @@ -1,5 +1,7 @@ + MinGW \t- Windows port of GNU Compiler Collection\n wxWidgets \t- Open-Source GUI framework\n wxFormBuilder\t- wxWidgets GUI-builder\n CodeBlocks \t- Open-Source IDE + Byte - Byte + 字节 GB GB MB @@ -8,14 +10,24 @@ PB TB TB + day(s) + 日 + hour(s) + 时 kB kB + min + 分 + sec + 秒 != files are different\n != 文件不同\n %x directories %x 目录 %x files, %x 文件, +%x is not a valid FreeFileSync batch file! +%x 无有效的 FreeFileSync 批处理文件 %x of %y rows in view %x of %y 横向视图 %x of 1 row in view @@ -30,8 +42,8 @@ 应用(&Y) &Cancel 撒消(&C) -&Compare -比较(&C) +&Check for new version +检查更新(&C) &Create batch job 创建批处理作业(&C) &Default @@ -52,6 +64,8 @@ 加载(&L) &Load configuration 加载配置(&L) +&No + &OK 确定(&O) &Pause @@ -62,16 +76,18 @@ 重试(&R) &Save 保存(&S) -&Start -开始(&S) -&Synchronize... -同步(&S)... +&Yes + , . +- do not copy\n + +- conflict + +- conflict (same date, different size) + - different - 不同 -- different (same date, different size) -- 不同 (日期相同,大小不同) - equal - 相同 - exists left only @@ -86,26 +102,30 @@ - 右侧 - right newer - 右侧较新 -- same date (different size) -- 日期相同 (大小不同) +-> copy to right side\n + -Open-Source file synchronization- -开源文件同步器- . , +/sec +/秒 1 directory 1 目录 1 file, 1 文件, 1. &Compare 1. 比较(&C) -1. Enter full file or directory names separated by ';' or a new line. -1. 输入完整的文件名或目录名(用";"号或一个新行) +1. Enter relative file or directory names separated by ';' or a new line. + 2. &Synchronize... 2. 同步(&S)... 2. Use wildcard characters '*' and '?'. 2. 使用通配符"*"和"?". 3. Exclude files directly on main grid via context menu. 3. 直接通过上下文菜单的主要网格排除文件. +<- copy to left side\n + << left file is newer\n << 左侧文件较新\n <Directory> @@ -116,10 +136,12 @@ <多选> <| file on left side only\n <| 仅左侧文件\n -== files are equal\n\n -== 文件相同\n\n +== files are equal\n + >> right file is newer\n >> 右侧文件较新\n +A newer version of FreeFileSync is available: +FreeFileSync 有新版可用: Abort requested: Waiting for current operation to finish... 取消请求: 正在等待当前操作完成... Aborted @@ -147,17 +169,21 @@ Batch file created successfully! Batch job 批处理作业 Big thanks for localizing FreeFileSync goes out to: -非常感谢做本地化FreeFileSync工作的以下人员: +非常感谢以下本地化 FreeFileSync 的工作人员: +Browse +浏览 Build: 开发: Cancel -放弃 +取消 Check all 检查所有 Choose to hide filtered files/directories from list 从列表中选择隐藏过滤文件/文件夹 Comma separated list 逗号分隔的列表 +Compare + Compare both sides 两侧比较 Compare by \"File content\" @@ -170,8 +196,10 @@ Comparing content 正在比较内容 Comparing content of files %x 正在比较档案内容的百分比 %x -Comparing... -比较中... +Comparing content... + +Comparison Result + Completed 完成 Configuration @@ -208,12 +236,12 @@ Copy to clipboard\tCTRL+C 复制到剪贴板\t使用CTRL+C键 Copying file %x to %y 正复制文件 %x 到 %y +Copying file %x to %y overwriting target +复制文件 %x 并覆盖到目标 %y Could not set working directory: 无法设置工作目录: Create a batch job 创建一个批工作 -Create: -创建: Creating folder %x 正创建文件夹 %x Current operation: @@ -226,8 +254,6 @@ DECISION TREE 决策树 Data remaining: 剩余数据: -Data: -数据: Date 日期 Delete files/folders existing on left side only @@ -240,16 +266,18 @@ Delete on both sides 删除两侧 Delete on both sides even if the file is selected on one side only 删除两侧(仅对在一侧已选择文件) -Delete: -删除: Deleting file %x 正删除文件 %x Deleting folder %x 正删除文件夹 %x Directories are dependent! Be careful when setting up synchronization rules: 目录有依赖性!注意设立同步的规则: +Directory +目录 Directory does not exist: 目录不存在: +Do not display visual status information but write to a logfile instead +不显示视觉状态信息,使用写入日志文件代替。 Do not show this warning again 不再显示警告信息 Do nothing @@ -258,10 +286,20 @@ Do you really want to delete the following objects(s)? 你确定要删除下列项目吗? Do you really want to move the following objects(s) to the Recycle Bin? 你确定要移动下列项目到回收站吗? +Do you want FreeFileSync to automatically check for updates every week? +要让 FreeFileSync 保持每周检查一次更新吗?> +Don't ask me again + Donate with PayPal 通过PayPal捐赠 +Download now? +立即下载? Drag && drop 拖拽 +Email +邮箱 +Enable filter to exclude files from synchronization +启用同步时使用过滤排除文件。 Error 错误 Error changing modification time: @@ -290,6 +328,8 @@ Error reading file: 读取文件出错: Error resolving symbolic link: 解决字符链接出错: +Error retrieving full path: +获取完整路径时出错: Error traversing directory: 遍历目录出错: Error writing file attributes: @@ -314,10 +354,14 @@ Feedback and suggestions are welcome at: 欢迎在下面提出反馈意见和建议: File Manager integration: 文件管理集成器: +File Time tolerance (seconds): +文件时间容错(秒): File already exists. Overwrite? 文件已经存在.覆盖? File content 文件内容 +File does not exist: +文件不存在: File list exported! 文件清单已经列出! File size and date @@ -334,8 +378,6 @@ Files remaining: 其余档案: Files that exist on both sides and have different content 两侧都有但内容不同的文件 -Files that exist on both sides, have same date but different filesizes -两侧都有且日期相同但文件大小不同的文件 Files that exist on both sides, left one is newer 两侧都有但左侧较新的文件 Files that exist on both sides, right one is newer @@ -348,6 +390,8 @@ Files/folders that exist on left side only 仅在左侧存在的档案/文件夹 Files/folders that exist on right side only 仅在左侧存在的档案/文件夹 +Filter +过滤 Filter active: Press again to deactivate 过滤激活: 请按键以关闭激活 Filter files @@ -368,8 +412,10 @@ FreeFileSync batch file FreeFileSync 批处理文件 FreeFileSync configuration FreeFileSync 配置 -Full name -全称 +FreeFileSync is up to date! +FreeFileSync 已是最新! +Full path + Generating file list... 生成文件列表... Global settings @@ -378,6 +424,8 @@ Help 帮助 Hide all error and warning messages 隐藏所有错误与警告信息 +Hide conflicts + Hide files that are different 隐藏不同的档案 Hide files that are equal @@ -390,6 +438,12 @@ Hide files that exist on left side only 仅隐藏在左侧的档案 Hide files that exist on right side only 仅隐藏在右侧的档案 +Hide files that will be copied to the left side + +Hide files that will be copied to the right side + +Hide files that won't be copied + Hide filtered items 隐藏已过滤的项目 Hide further error messages during the current process @@ -398,6 +452,12 @@ Hides error messages during synchronization:\nThey are collected and shown as a 隐藏同步时的错误信息:在结束进程时收集和显示的清单 Hints: 提示: +Homepage +主页 +If you like FFS +如果你喜欢 FFS +Ignore 1-hour file time difference + Ignore errors 忽略错误 Ignore subsequent errors @@ -410,8 +470,8 @@ Include 包括 Include temporarily 包括暂时的 -Include: *.doc;*.zip;*.exe\nExclude: *\\temp\\* -包括:*.doc;*.zip;*.exe 除外:*\\temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\temp\\* + Info 信息 Information @@ -420,24 +480,30 @@ Initialization of Recycle Bin failed! 初始化回收站失败! It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) 初始化回收站是不大可能了!估计你使用的不是Windows系统.如果你想未来在此系统上应用请联系作者. :) -Legend -联想 +Left: +左侧: Load configuration from file 从文件加载配置 Load configuration history (press DEL to delete items) 加载配置历史记录(按DEL键删除项目) Log-messages: 日志信息: +Logging +记录 Mirror ->> 镜像 ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. 左侧文件夹镜像备份: 同步后右侧文件夹将被覆盖(完全匹配左边的文件夹). +More than 50% of the total number of files will be copied or deleted! +超过总数的 50% 以上的文件要被删除或复制 Move column down 移动下一行 Move column up 移动上一行 -Not all items were synchronized! Have a look at the list. -不是所有项目被同步!看一下列表 +Not all items have been synchronized! Have a look at the list. + +Not enough free disk space available in: +无足够的可用空间于: Nothing to synchronize according to configuration! 根据配置没有任何同步! Number of files and directories that will be created @@ -448,18 +514,20 @@ Number of files that will be overwritten 一些文件和目录将被覆盖 OK 确定 -Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the full name including path prefix. -只有过滤的文件/目录将选定做同步.该过滤器将被应用到全称包括路径前缀. -Open synchronization dialog -打开同步对话框 +Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the name relative(!) to the synchronization directories. + Open with File Manager\tD-Click -打开文件管理 +在资源管理器中打开 Operation aborted! 操作已取消! Operation: 操作: +Overview +摘要 Pause 暂停 +Paused +已暂停 Please fill all empty directory fields. 请填满所有空的目录区域. Press button to activate filter @@ -468,6 +536,8 @@ Preview 视图 Published under the GNU General Public License: 在GNU通用公共许可下发布: +Question + Quit 退出 Relative path @@ -476,16 +546,20 @@ Remove folder pair 删除文件夹对 Reset 重置 +Reset all warning messages + Reset all warning messages? 重置所有警告信息? -Resets all warning messages -重置所有警告信息 Result 结果 +Right: +右侧: S&ave configuration 保存配置(&A) -Save aborted! -保存失败! +S&witch view + +Save changes to current configuration? + Save current configuration to file 保存当前配置到文件 Scanning... @@ -494,8 +568,14 @@ Scanning: 扫描中: Select a folder 选择一个文件夹 +Select logfile directory: +选择日志保存位置: Select variant: 选择变化的: +Show conflicts + +Show file icons + Show files that are different 显示不同的文件 Show files that are equal @@ -508,10 +588,18 @@ Show files that exist on left side only 显示仅存在左侧的文件 Show files that exist on right side only 显示仅存在右侧的文件 +Show files that will be copied to the left side + +Show files that will be copied to the right side + +Show files that won't be copied + Show popup 查看弹出 Show popup on errors or warnings 查看弹出的错误或警告 +Significant difference detected: +已侦测到显著不同: Silent mode 静默模式 Size @@ -520,6 +608,8 @@ Sorting file list... 排序文件列表... Source code written completely in C++ utilizing: 使用C++编写的源代码已完全写好: +Speed: +速度: Start 开始 Start synchronization @@ -528,6 +618,8 @@ Stop 停止 Swap sides 换边 +Synchronization Preview + Synchronization aborted! 同步已放弃! Synchronization completed successfully! @@ -540,8 +632,8 @@ Synchronization settings 同步设置 Synchronization status 同步状态 -Synchronize all .doc, .zip and .exe files except everything from folder \"temp\". -同步所有的 .doc, .zip und .exe的文件( 文件夹 \"temp\"下的所有文件除外). +Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". + Synchronize both sides simultaneously: Copy new or updated files in both directions. 同时同步两侧: 复制新的或更新的文件在两个方向. Synchronizing... @@ -560,22 +652,30 @@ Time 时间 Time elapsed: 已用时间: +Time remaining: +剩余时间: Total amount of data that will be transferred 将被转移的总数据 +Total required free disk space: +所需可用磁盘空间总量: Total time: 总共时间: +Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes. + Two way <-> 两侧 <-> +Unable to connect to sourceforge.net! +无法链接到 Sourceforge.net! Unable to create logfile! 无法创建日志! Unable to initialize Recycle Bin! 无法初始化回收站! Uncheck all 全部取消选中 +Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. + Update -> 升级 -> -Update: -升级: Use Recycle Bin 使用回收站 Use Recycle Bin when deleting or overwriting files during synchronization @@ -594,7 +694,9 @@ different 不同 file exists on both sides 两侧文件已存在 +flash conflict\n + on one side only 仅在一侧 |> file on right side only\n -|> 仅在可侧的文件\n +|> 仅右侧文件\n diff --git a/Languages/dutch.lng b/Languages/dutch.lng index 1a35e1f3..5e00740f 100644 --- a/Languages/dutch.lng +++ b/Languages/dutch.lng @@ -44,8 +44,6 @@ &Annuleren &Check for new version &Controleer op nieuwe versie -&Compare -&Vergelijken &Create batch job &Creëer batchjob &Default @@ -66,6 +64,8 @@ &Laden &Load configuration &Laad de configuratie +&No +&Nee &OK &OK &Pause @@ -76,16 +76,18 @@ &Opnieuw proberen &Save &Opslaan -&Start -&Start -&Synchronize... -&Synchroniseer... +&Yes +&Ja , . +- do not copy\n +- niet kopiëren\n +- conflict +- conflict +- conflict (same date, different size) +- conflict (zelfde datum, verschillende grootte) - different - verschillend -- different (same date, different size) -- verschillend (zelfde datum, verschillende grootte) - equal - gelijk - exists left only @@ -100,8 +102,8 @@ - rechts - right newer - rechts is nieuwer -- same date (different size) -- zelfde datum (verschillende grootte) +-> copy to right side\n +-> kopieer naar de rechterkant\n -Open-Source file synchronization- -Open-Source bestandssynchronisatie- . @@ -114,16 +116,16 @@ 1 bestand, 1. &Compare 1. &Vergelijk -1. Enter full file or directory names separated by ';' or a new line. -1. Geef de volledige naam van het bestand of pad gescheiden bij ';' of een nieuwe regel. +1. Enter relative file or directory names separated by ';' or a new line. +1. Vul de relatieve bestandsnaam of map in, gescheiden bij ';' of een nieuwe regel. 2. &Synchronize... 2. &Synchroniseer... 2. Use wildcard characters '*' and '?'. 2. U kunt gebruik maken van wildcard karakters zoals '*' en '?'. 3. Exclude files directly on main grid via context menu. 3. Sluit bestanden direct uit in het hoofscherm via een contextmenu -4. Keep the number of (different) entries small for best performance. -4. Hou het aantal (verschillende) posten klein voor de beste prestaties. +<- copy to left side\n +<- kopieer naar de linkerkant\n << left file is newer\n << linker bestand is nieuwer\n <Directory> @@ -134,8 +136,8 @@ <veelvoudige selectie> <| file on left side only\n <| bestand bestaat alleen links\n -== files are equal\n\n -== bestanden zijn gelijk\n\n +== files are equal\n +== bestanden zijn gelijk\n >> right file is newer\n >> rechter bestand is nieuwer\n A newer version of FreeFileSync is available: @@ -168,6 +170,8 @@ Batch job Batch taak Big thanks for localizing FreeFileSync goes out to: Extra dank voor het vertalen van FreeFileSync gaat naar: +Browse +Bestand opzoeken Build: Gebouwd: Cancel @@ -178,6 +182,8 @@ Choose to hide filtered files/directories from list Gefilterde bestanden niet/wel weergeven Comma separated list Komma gescheiden lijst +Compare +Vergelijk Compare both sides Beide zijden vergelijken Compare by \"File content\" @@ -190,8 +196,10 @@ Comparing content Vergelijken van inhoud Comparing content of files %x De inhoud van %x bestanden wordt vergeleken -Comparing... -Vergelijken... +Comparing content... +Inhoud vergelijken... +Comparison Result +Resultaat vergelijken Completed Volbracht Configuration @@ -234,8 +242,6 @@ Could not set working directory: Kan het pad in gebruik niet instellen: Create a batch job Creëer batchjob -Create: -Aanmaken: Creating folder %x Map %x wordt aangemaakt Current operation: @@ -248,8 +254,6 @@ DECISION TREE BESLISSINGSBOOM Data remaining: Resterende data: -Data: -Data: Date Datum Delete files/folders existing on left side only @@ -262,8 +266,6 @@ Delete on both sides Verwijder aan beide kanten Delete on both sides even if the file is selected on one side only Verwijder aan beide kanten ookal is het bestand maar aan één kant geselecteerd -Delete: -Verwijderen: Deleting file %x Bestand %x wordt verwijderd Deleting folder %x @@ -286,6 +288,8 @@ Do you really want to move the following objects(s) to the Recycle Bin? Weet u zeker dat u de/het volgende bestand(en) wilt verplaatsen naar de prullenbak? Do you want FreeFileSync to automatically check for updates every week? Wilt u FreeFileSync automatisch elke week laten controleren of er een nieuwe versie is? +Don't ask me again +Niet meer vragen Donate with PayPal Doneer met PayPal Download now? @@ -374,8 +378,6 @@ Files remaining: Resterende bestanden: Files that exist on both sides and have different content Bestanden die aan beide kanten bestaan maar een verschillende inhoud hebben -Files that exist on both sides, have same date but different filesizes -Bestanden die aan beide kanten bestaan, dezelfde datum hebben maar verschillende bestandgroottes Files that exist on both sides, left one is newer Bestanden die aan beide kanten bestaan, maar waarvan de linkerkant nieuwer is Files that exist on both sides, right one is newer @@ -412,8 +414,8 @@ FreeFileSync configuration FreeFileSync configuratie FreeFileSync is up to date! U gebruikt de nieuwste versie van FreeFileSync! -Full name -Volledige naam +Full path +Volledige bestandslocatie Generating file list... Bestandslijst genereren... Global settings @@ -422,6 +424,8 @@ Help Help Hide all error and warning messages Verberg alle foutmeldingen en waarschuwingen +Hide conflicts +Verberg conflicten Hide files that are different Verberg bestanden die verschillend zijn Hide files that are equal @@ -434,6 +438,12 @@ Hide files that exist on left side only Verberg bestanden die alleen aan de linkerkant bestaan Hide files that exist on right side only Verberg bestanden die alleen aan de rechterkant bestaan +Hide files that will be copied to the left side +Verberg bestanden die naar de linkerkant zullen worden gekopieerd +Hide files that will be copied to the right side +Verberg bestanden die naar de rechterkant zullen worden gekopieerd +Hide files that won't be copied +Verberg bestanden die niet zullen worden gekopieerd Hide filtered items Verberg gefilterde items Hide further error messages during the current process @@ -446,6 +456,8 @@ Homepage Homepage If you like FFS Als het programma u bevalt +Ignore 1-hour file time difference +Negeer 1-uur bestandstijd verschillen Ignore errors Negeer foutmeldingen Ignore subsequent errors @@ -458,8 +470,8 @@ Include Gebruiken Include temporarily Tijdelijk bijsluiten -Include: *.doc;*.zip;*.exe\nExclude: *\\temp\\* -Gebruiken: *.doc;*.zip;*.exe\nUitsluiten: *\\temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\temp\\* +Bijsluiten: *.doc;*.zip;*.exe\nUitsluiten: \\temp\\* Info Info Information @@ -470,8 +482,6 @@ It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are n Het was niet mogelijk de prullenbak te initialiseren!\n\nHet is waarschijnlijk dat u niet Windows gebruikt.\nAls u deze optie wel wilt, neem dan alstublieft contact op met de auteur. :) Left: Links: -Legend -Legenda Load configuration from file Laad configuratie uit bestand Load configuration history (press DEL to delete items) @@ -490,7 +500,7 @@ Move column down Verplaats kolom naar beneden Move column up Verplaats kolom naar boven -Not all items were synchronized! Have a look at the list. +Not all items have been synchronized! Have a look at the list. Niet alle bestanden zijn gesynchroniseerd! Bekijk de lijst. Not enough free disk space available in: Niet genoeg schijfruimte beschikbaar op: @@ -504,10 +514,8 @@ Number of files that will be overwritten Aantal bestanden dat zal worden overschreven OK OKE -Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the full name including path prefix. -Alleen de niet gefilterde bestanden worden geselecteerd voor synchronisatie. Het filter wordt toegepast op de volledige naam inclusief pad-voorvoegsel. -Open synchronization dialog -Open de synchronisatie-instellingen +Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the name relative(!) to the synchronization directories. +Alleen bestanden/mappen die niet zijn gefilterd worden geselecteerd voor synchronisatie. Het filter wordt toegepast op de naam relatief(!) ten opzichte van de synchronisatiemappen. Open with File Manager\tD-Click Openen met bestandsbeheerder\tD-klik Operation aborted! @@ -528,6 +536,8 @@ Preview Voorbeeld Published under the GNU General Public License: Gepubliceerd onder de GNU General Public License: +Question +Vraag Quit Afsluiten Relative path @@ -536,18 +546,20 @@ Remove folder pair Verwijder 1 paar gekoppelde mappen Reset Reset +Reset all warning messages +Reset alle waarchuwingen Reset all warning messages? Reset alle waarschuwingen? -Resets all warning messages -Reset alle waarschuwingen Result Resultaat Right: Rechts: S&ave configuration S&la de instellingen op -Save aborted! -Sla de afgebroken bestanden op! +S&witch view +&Wijzig weergave +Save changes to current configuration? +Sla veranderingen op in de huidige configuratie? Save current configuration to file Sla de huidige instellingen op in een bestand Scanning... @@ -560,6 +572,10 @@ Select logfile directory: Selecteer een map voor het logbestand: Select variant: Selecteer een variant: +Show conflicts +Geef conflicten weer +Show file icons +Geef bestandsiconen weer Show files that are different Geef bestanden die verschillend zijn weer Show files that are equal @@ -572,6 +588,12 @@ Show files that exist on left side only Geef bestanden weer die alleen bestaan aan de linkerkant Show files that exist on right side only Geef bestanden weer die alleen bestaan aan de rechterkant +Show files that will be copied to the left side +Geef bestanden weer die naar de linkerkant worden gekopieerd +Show files that will be copied to the right side +Geef bestanden weer die naar de rechterkant worden gekopieerd +Show files that won't be copied +Geef bestanden weer die niet zullen worden gekopieerd Show popup Pop-up weergeven Show popup on errors or warnings @@ -596,6 +618,8 @@ Stop Stop Swap sides Verwissel van kant +Synchronization Preview +Synchronisatie voorbeeldweergave Synchronization aborted! Synchronisatie afgebroken! Synchronization completed successfully! @@ -608,8 +632,8 @@ Synchronization settings Synchronisatie instellingen Synchronization status Synchronisatie: status -Synchronize all .doc, .zip and .exe files except everything from folder \"temp\". -Synchroniseer alle .doc, .zip en .exe bestanden behalve alles uit de map \"temp\". +Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". +Synchroniseer alle .doc, .zip en .exe bestanden uitgezonderd alles in submap \"temp\" Synchronize both sides simultaneously: Copy new or updated files in both directions. Synchroniseer beide zijde tegelijkertijd: kopieer nieuwe of geüpdatete bestanden in beide richtingen. Synchronizing... @@ -636,6 +660,8 @@ Total required free disk space: Benodigde hoeveelheid vrije schijfruimte: Total time: Totale tijd: +Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes. +Behandel bestandstijden die verschillen met precies +/- 1 uur als gelijk en minder als 1 uur als conflict om zomertijd veranderingen te verwerken. Two way <-> Beide zijden <-> Unable to connect to sourceforge.net! @@ -646,10 +672,10 @@ Unable to initialize Recycle Bin! De prullenbak kon niet worden geïnitialiseerd! Uncheck all Alles uitvinken +Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. +Er bestaan onopgeloste conflicten! \n\nU kunt de conflicten negeren en doorgaan met synchroniseren. Update -> Overschrijven -> -Update: -Overschrijven: Use Recycle Bin Gebruik de prullenbak Use Recycle Bin when deleting or overwriting files during synchronization @@ -668,6 +694,8 @@ different verschillend file exists on both sides Bestand bestaat aan beide zijde +flash conflict\n +knipperen conflict\n on one side only alleen aan één kant |> file on right side only\n diff --git a/Languages/french.lng b/Languages/french.lng index f970f508..fcf148d5 100644 --- a/Languages/french.lng +++ b/Languages/french.lng @@ -44,8 +44,6 @@ &Annuler &Check for new version &Rechercher une nouvelle version -&Compare -&Comparer &Create batch job &Créer un fichier de commandes &Default @@ -66,6 +64,8 @@ &Charger &Load configuration &Charger la configuration +&No +&Non &OK &OK &Pause @@ -76,16 +76,18 @@ &Réessayer &Save &Sauvegarder -&Start -&Démarrer -&Synchronize... -&Synchroniser... +&Yes +&Oui , +- do not copy\n +- ne pas copier\n +- conflict +- conflit +- conflict (same date, different size) +- conflit (même date, taille différente) - different - fichiers différents -- different (same date, different size) -- fichiers différents (même date, taille différente) - equal - fichiers identiques - exists left only @@ -100,8 +102,8 @@ - à droite - right newer - fichier de droite plus récent -- same date (different size) -- même date (taille différente) +-> copy to right side\n +-> copier à droite\n -Open-Source file synchronization- -Synchronisation de fichiers Open-Source- . @@ -114,16 +116,16 @@ 1 fichier, 1. &Compare 1. &Comparer -1. Enter full file or directory names separated by ';' or a new line. -1. Entrez le nom complet des fichiers ou des dossier séparés par un ';' ou par un 'retour chariot'. +1. Enter relative file or directory names separated by ';' or a new line. +1. Entrez les noms relatifs des fichiers ou des répertoires séparés par un ';' ou par un passage à la ligne. 2. &Synchronize... 2. &Synchroniser... 2. Use wildcard characters '*' and '?'. 2. Les caractères génériques '*' et '?' sont acceptés. 3. Exclude files directly on main grid via context menu. 3. Exclure les fichiers directement sur le tableau principal à l'aide du menu contextuel. -4. Keep the number of (different) entries small for best performance. -4. Réduire le nombre d'entrées (différentes) pour une meilleure performance +<- copy to left side\n +<- copier à gauche\n << left file is newer\n << le fichier de gauche est plus récent\n <Directory> @@ -134,12 +136,12 @@ <sélection multiple> <| file on left side only\n <| Le fichier existe seulement à gauche\n -== files are equal\n\n -== Les fichiers sont identiques\n\n +== files are equal\n +== les fichiers sont identiques\n >> right file is newer\n >> le fichier de droite est plus récent\n A newer version of FreeFileSync is available: -Une version de FreeFileSync plus récente est disponible: +Une version plus récente de FreeFileSync est disponible: Abort requested: Waiting for current operation to finish... Abandon demandé: En attente de la fin de l'opération en cours... Aborted @@ -153,7 +155,7 @@ Ajout d'un couple de dossiers All items have been synchronized! Tous les éléments ont été synchronisés! An exception occured! -Une violation s'est produite! +Une violation s'est produite ! As a result the files are separated into the following categories: En conclusion, les fichiers sont répartis dans les catégories suivantes: As the name suggests, two files which share the same name are marked as equal if and only if they have the same content. This option is useful for consistency checks rather than backup operations. Therefore the file times are not taken into account at all.\n\nWith this option enabled the decision tree is smaller: @@ -168,6 +170,8 @@ Batch job Fichier de commandes Big thanks for localizing FreeFileSync goes out to: Pour les traductions de FreeFileSync, un grand merci à: +Browse +Parcourir Build: Créé: Cancel @@ -178,6 +182,8 @@ Choose to hide filtered files/directories from list Masquer les fichiers/répertoires filtrés Comma separated list Liste d'éléments séparés par une virgule +Compare +Comparer Compare both sides Comparer les deux listes Compare by \"File content\" @@ -189,9 +195,11 @@ Comparaison par... Comparing content Comparaison du contenu Comparing content of files %x -comparaison du contenu des fichiers %x -Comparing... -Comparaison en cours... +Comparaison du contenu des fichiers %x +Comparing content... +Comparaison du contenu... +Comparison Result +Résultat de la comparaison Completed Terminé Configuration @@ -234,12 +242,10 @@ Could not set working directory: Impossible de définir le répertoire de travail: Create a batch job Création du fichier de commandes -Create: -Créations: Creating folder %x Création du dossier %x Current operation: -Opération en cours: +Opération en cours : Custom Personnaliser Customize columns @@ -247,9 +253,7 @@ Personnaliser les colonnes DECISION TREE ARBRE DE DECISION Data remaining: -Données restantes: -Data: -Données: +Données restantes : Date Date Delete files/folders existing on left side only @@ -262,8 +266,6 @@ Delete on both sides Suppression des deux côtés Delete on both sides even if the file is selected on one side only Suppression des deux côtés même si le fichier est sélectionné d'un seul côté -Delete: -Suppressions: Deleting file %x Suppression du fichier %x Deleting folder %x @@ -274,6 +276,8 @@ Directory Répertoire Directory does not exist: Le répertoire n'existe pas: +Do not display visual status information but write to a logfile instead +Ne pas afficher les informations d'état à l'écran mais les enregistrer plutôt dans un fichier log Do not show this warning again Ne plus afficher cet avertissement Do nothing @@ -281,9 +285,11 @@ Ne rien faire Do you really want to delete the following objects(s)? Voulez-vous vraiment supprimer les objets suivants ? Do you really want to move the following objects(s) to the Recycle Bin? -Voulez-vous vraiment déplacer les objets suivants dans la corbeille? +Voulez-vous vraiment déplacer les objets suivants dans la corbeille ? Do you want FreeFileSync to automatically check for updates every week? Voulez-vous que FreeFileSync recherche automatiquement de nouvelles versions chaque semaine ? +Don't ask me again +Ne plus me redemander Donate with PayPal Faites un don avec PayPal Download now? @@ -345,7 +351,7 @@ Sortie immédiate avec le returncode < 0 Exit with RC < 0 Sortie avec RC < 0 Feedback and suggestions are welcome at: -Commentaires et suggestions sont les bienvenus à: +Commentaires et suggestions sont les bienvenus à : File Manager integration: Choix du Gestionnaire de Fichiers: File Time tolerance (seconds): @@ -372,8 +378,6 @@ Files remaining: Fichiers restants: Files that exist on both sides and have different content Les fichiers existent des deux côtés et ont des contenus différents -Files that exist on both sides, have same date but different filesizes -Les fichiers existent des deux côtés, ont la même date mais des tailles différentes Files that exist on both sides, left one is newer Fichiers existants des deux côtés, celui de gauche est plus récent Files that exist on both sides, right one is newer @@ -410,8 +414,8 @@ FreeFileSync configuration FreeFileSync configuration FreeFileSync is up to date! FreeFileSync a été mis à jour ! -Full name -Nom complet +Full path +Chemin complet Generating file list... Génération de la liste des fichiers... Global settings @@ -420,6 +424,8 @@ Help Aide Hide all error and warning messages Masquer tous les messages d'erreurs et les avertissements +Hide conflicts +Conflits sur le masquage Hide files that are different Masquer les fichiers différents Hide files that are equal @@ -432,6 +438,12 @@ Hide files that exist on left side only Masquer les fichiers existant des deux côtés Hide files that exist on right side only Masquer les fichiers n'existant qu'à droite +Hide files that will be copied to the left side +Masquer les fichiers qui seront copiés à gauche +Hide files that will be copied to the right side +Masquer les fichiers qui seront copiés à droite +Hide files that won't be copied +Masquer les fichiers qui ne seront pas copiés Hide filtered items Masquer les éléments filtrés Hide further error messages during the current process @@ -444,6 +456,8 @@ Homepage Accueil If you like FFS Si vous aimez FFS +Ignore 1-hour file time difference +Ignorer les diférences d'une heure Ignore errors Ignorer les erreurs Ignore subsequent errors @@ -456,8 +470,8 @@ Include Inclure Include temporarily Inclure temporairement -Include: *.doc;*.zip;*.exe\nExclude: *\\temp\\* -Inclure: *.doc;*.zip;*.exe\nExclude: *\\temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\temp\\* +Inclure: *.doc;*.zip;*.exe\nExclure: \\temp\\* Info Info Information @@ -468,8 +482,6 @@ It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are n Impossible d'accéder à la corbeille!\n\nIl est probable que vous n'utilisez pas Windows.\nSi vous désirez utilisee cette fonctionnalité, veuillez contacter l'auteur. :) Left: Gauche: -Legend -Legende Load configuration from file Charger la configuration à partir du fichier Load configuration history (press DEL to delete items) @@ -488,8 +500,8 @@ Move column down Déplacer la colonne vers le bas Move column up Déplacer la colonne vers le haut -Not all items were synchronized! Have a look at the list. -Tous les éléments n'ont pas été synchronisés! Veuillez vérifier la liste. +Not all items have been synchronized! Have a look at the list. +Tout n'a pas été synchronisé ! Vérifiez la liste. Not enough free disk space available in: Espace disque insuffisant sur : Nothing to synchronize according to configuration! @@ -502,10 +514,8 @@ Number of files that will be overwritten Nombre de fichiers qui seront remplacés OK OK -Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the full name including path prefix. -Seuls les fichiers/dossiers filtrés seront sélectionnés pour la synchronisation.\nLe filtre s'appliquera au nom complet incluant le chemin. -Open synchronization dialog -Ouvrir la boîte de dialogue de la synchronisation +Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the name relative(!) to the synchronization directories. +Seuls les fichiers/répertoires filtrés seront sélectionnés pour la synchronisation. Le filtre sera appliqué aux noms relatifs pour la synchronisation. Open with File Manager\tD-Click Ouvrir avec le Gestionnaire de Fichiers\tClick droit Operation aborted! @@ -526,6 +536,8 @@ Preview Prévoir Published under the GNU General Public License: Publié sous la licence GNU General Public: +Question +Question Quit Quitter Relative path @@ -534,18 +546,20 @@ Remove folder pair Supprimer le couple de dossiers Reset Réinitialiser +Reset all warning messages +Réinitialisation de tous les avertissements Reset all warning messages? Réinitialiser tous les avertissements? -Resets all warning messages -Réinitialise tous les avertissements Result Situation Right: Droite : S&ave configuration S&auvegarder la configuration -Save aborted! -Sauvegarde abandonnée! +S&witch view +Changer de &vue +Save changes to current configuration? +Voulez-vous enregistrer les modifications dans la configuration courante ? Save current configuration to file Enregistrer la configuration courante Scanning... @@ -558,6 +572,10 @@ Select logfile directory: Choisissez un dossier pour le fichier .log Select variant: Choisissez une variante: +Show conflicts +Afficher les conflits +Show file icons +Afficher les icônes Show files that are different Afficher les fichiers différents Show files that are equal @@ -570,8 +588,14 @@ Show files that exist on left side only Afficher les fichiers existants seulement à gauche Show files that exist on right side only Afficher les fichiers existants seulement à droite +Show files that will be copied to the left side +Afficher les ficgier qui seront copiés à gauche +Show files that will be copied to the right side +Afficher les ficgier qui seront copiés à droite +Show files that won't be copied +Afficher les ficgier qui ne seront pas copiés Show popup -Affich +Afficher la boîte de dialogue Show popup on errors or warnings Affiche une boîte de dialogue pour chaque erreur ou avertissement Significant difference detected: @@ -594,6 +618,8 @@ Stop Arrêt Swap sides Permuter les côtés +Synchronization Preview +Prévisualisation de la synchronisation Synchronization aborted! Synchronisation abandonnée! Synchronization completed successfully! @@ -606,8 +632,8 @@ Synchronization settings Paramétrage de la synchronisation Synchronization status Etat de la synchronisation -Synchronize all .doc, .zip and .exe files except everything from folder \"temp\". -Synchroniser tous les fichiers .doc, .zip and .exe sauf ceux du dossier \"temp\". +Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". +Synchroniser rous les fichiers .doc, .zip et .exe sauf ceux du dossier \"temp\". Synchronize both sides simultaneously: Copy new or updated files in both directions. Synchronisation simultanée des deux côtés. Copie des fichiers nouveaux ou mis à jour. Synchronizing... @@ -634,6 +660,8 @@ Total required free disk space: Espace disque nécessaire : Total time: Temps total: +Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes. +Traiter les heures qui différent exactement de +/- 1 heure comme égales, et celles qui diffèrent de moins d'une heure comme conflit sur la gestion de l'heure d'été. Two way <-> Des 2 côtés <-> Unable to connect to sourceforge.net! @@ -644,10 +672,10 @@ Unable to initialize Recycle Bin! Impossible d'initialiser la corbeille! Uncheck all Décocher tout +Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. +Il y a des conflits non résolus !\n\nVous pouvez ignorer ces conflits et continuer la synchronisation. Update -> Mise à Jour -> -Update: -Mises à jour: Use Recycle Bin Utilisation de la corbeille Use Recycle Bin when deleting or overwriting files during synchronization @@ -666,6 +694,8 @@ different fichiers différents file exists on both sides Le fichier existe des deux côtés +flash conflict\n +flash conflit\n on one side only Le fichier existe sur un seul côté seulement |> file on right side only\n diff --git a/Languages/german.lng b/Languages/german.lng index caa12ac1..01b69eb9 100644 --- a/Languages/german.lng +++ b/Languages/german.lng @@ -1,8 +1,6 @@ MinGW \t- Windows port of GNU Compiler Collection\n wxWidgets \t- Open-Source GUI framework\n wxFormBuilder\t- wxWidgets GUI-builder\n CodeBlocks \t- Open-Source IDE MinGW \t- Windows port of GNU Compiler Collection\n wxWidgets \t- Open-Source GUI Framework\n wxFormBuilder\t- wxWidgets GUI-Builder\n CodeBlocks \t- Open-Source IDE -Browse -Suchen - Byte + Byte Byte GB GB @@ -41,13 +39,11 @@ Suchen &Advanced &Erweitert &Apply -&Übernehmen +&Anwenden &Cancel &Abbrechen &Check for new version &Auf neuere Version prüfen -&Compare -&Vergleichen &Create batch job &Batch-Job erstellen &Default @@ -68,6 +64,8 @@ Dateiliste e&xportieren &Laden &Load configuration Konfiguration &laden +&No +&Nein &OK &OK &Pause @@ -78,16 +76,18 @@ Konfiguration &laden &Wiederholen &Save &Speichern -&Start -&Start -&Synchronize... -&Synchronisieren +&Yes +&Ja , . +- do not copy\n +- nicht kopieren\n +- conflict +- Konflikt +- conflict (same date, different size) +- Konflikt (gleiches Datum, unterschiedliche Größe) - different - verschieden -- different (same date, different size) -- verschieden (gleiches Datum, unterschiedliche Größe) - equal - gleich - exists left only @@ -102,8 +102,8 @@ Konfiguration &laden - rechts - right newer - rechts neuer -- same date (different size) -- gleiches Datum (unterschiedliche Größe) +-> copy to right side\n +-> nach rechts kopieren\n -Open-Source file synchronization- -Open-Source Datei-Synchronisation- . @@ -116,16 +116,16 @@ Konfiguration &laden 1 Datei, 1. &Compare 1. &Vergleichen -1. Enter full file or directory names separated by ';' or a new line. -1. Ganze Datei- und Verzeichnisnamen getrennt durch ';' oder eine Neuzeile eingeben. +1. Enter relative file or directory names separated by ';' or a new line. +1. Relative Datei- oder Verzeichnisnamen getrennt durch ';' oder eine Neuzeile eingeben. 2. &Synchronize... 2. &Synchronisieren... 2. Use wildcard characters '*' and '?'. 2. Die Platzhalter '*' und '?' werden unterstützt. 3. Exclude files directly on main grid via context menu. 3. Dateien können direkt über das Kontextmenü im Hauptfenster ausgeschlossen werden. -4. Keep the number of (different) entries small for best performance. -4. Für beste Performance möglichst wenige (verschiedene) Einträge filtern. +<- copy to left side\n +-> nach links kopieren\n << left file is newer\n << Linke Datei ist neuer\n <Directory> @@ -136,8 +136,8 @@ Konfiguration &laden <Mehrfachauswahl> <| file on left side only\n <| Datei existiert nur links\n -== files are equal\n\n -== Dateien sind gleich\n\n +== files are equal\n +== Dateien sind gleich\n >> right file is newer\n >> Rechte Datei ist neuer\n A newer version of FreeFileSync is available: @@ -170,6 +170,8 @@ Batch job Batch-Job Big thanks for localizing FreeFileSync goes out to: Vielen Dank für die Lokalisation von FreeFileSync an: +Browse +Auswählen Build: Build: Cancel @@ -180,6 +182,8 @@ Choose to hide filtered files/directories from list Gefilterte Dateien bzw. Verzeichnisse ein-/ausblenden Comma separated list Kommagetrennte Liste +Compare +Vergleichen Compare both sides Beide Seiten vergleichen Compare by \"File content\" @@ -192,8 +196,10 @@ Comparing content Vergleiche Dateiinhalt Comparing content of files %x Vergleiche Inhalt der Dateien %x -Comparing... -Vergleiche... +Comparing content... +Vergleiche Dateiinhalt... +Comparison Result +Ergebnis des Vergleichs Completed Fertig Configuration @@ -236,8 +242,6 @@ Could not set working directory: Das Arbeitsverzeichnis konnte nicht gesetzt werden: Create a batch job Batch-Job erstellen -Create: -Erstellen: Creating folder %x Erstelle Verzeichnis %x Current operation: @@ -250,8 +254,6 @@ DECISION TREE ENTSCHEIDUNGSBAUM Data remaining: Verbliebene Daten: -Data: -Daten: Date Datum Delete files/folders existing on left side only @@ -264,8 +266,6 @@ Delete on both sides Auf beiden Seiten löschen Delete on both sides even if the file is selected on one side only Lösche auf beiden Seiten, auch wenn die Datei nur auf einer Seite markiert ist -Delete: -Löschen: Deleting file %x Lösche Datei %x Deleting folder %x @@ -288,6 +288,8 @@ Do you really want to move the following objects(s) to the Recycle Bin? Sollen folgende Elemente wirklich in den Papierkorb verschoben werden? Do you want FreeFileSync to automatically check for updates every week? Soll FreeFileSync automatisch jede Woche nach Aktualisierungen suchen? +Don't ask me again +Nicht mehr nachfragen Donate with PayPal Mit PayPal spenden Download now? @@ -376,8 +378,6 @@ Files remaining: Verbliebene Dateien: Files that exist on both sides and have different content Auf beiden Seiten existierende Dateien mit unterschiedlichem Inhalt -Files that exist on both sides, have same date but different filesizes -Auf beiden Seiten existierende Dateien mit gleichem Datum aber verschiedenen Dateigrößen Files that exist on both sides, left one is newer Auf beiden Seiten existierende Dateien; linke Datei ist neuer Files that exist on both sides, right one is newer @@ -414,8 +414,8 @@ FreeFileSync configuration FreeFileSync Konfiguration FreeFileSync is up to date! FreeFileSync ist auf dem neuesten Stand! -Full name -Absoluter Name +Full path +Absoluter Pfad Generating file list... Erzeuge Dateiliste... Global settings @@ -424,6 +424,8 @@ Help Hilfe Hide all error and warning messages Alle Fehler- und Warnmeldungen werden unterdrückt +Hide conflicts +Konflikte ausblenden Hide files that are different Ungleiche Dateien ausblenden Hide files that are equal @@ -436,6 +438,12 @@ Hide files that exist on left side only Nur links existierende Dateien ausblenden Hide files that exist on right side only Nur rechts existierende Dateien ausblenden +Hide files that will be copied to the left side +Dateien die nach links kopiert werden ausblenden +Hide files that will be copied to the right side +Dateien die nach rechts kopiert werden ausblenden +Hide files that won't be copied +Dateien die nicht kopiert werden ausblenden Hide filtered items Gefilterte Elemente ausblenden Hide further error messages during the current process @@ -448,6 +456,8 @@ Homepage Homepage If you like FFS FFS unterstützen +Ignore 1-hour file time difference +Zeitunterschied von einer Stunde ignorieren Ignore errors Fehler ignorieren Ignore subsequent errors @@ -460,8 +470,8 @@ Include Einschließen Include temporarily Temporär einschließen -Include: *.doc;*.zip;*.exe\nExclude: *\\temp\\* -Einschließen: *.doc;*.zip;*.exe\nAusschließen: *\\temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\temp\\* +Einschließen: *.doc;*.zip;*.exe\nAusschließen: \\temp\\* Info Info Information @@ -472,8 +482,6 @@ It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are n Die Papierkorbfunktion steht nicht zur Verfügung!\n\nWahrscheinlich benutzen Sie nicht Microsoft Windows.\nWenn Sie diese Funktion wirklich benötigen, kontaktieren Sie bitte den Autor. :) Left: Links: -Legend -Legende Load configuration from file Konfiguration aus Datei laden Load configuration history (press DEL to delete items) @@ -492,7 +500,7 @@ Move column down Spalte nach unten verschieben Move column up Spalte nach oben verschieben -Not all items were synchronized! Have a look at the list. +Not all items have been synchronized! Have a look at the list. Nicht alle Elemente wurden synchronisiert! Siehe verbliebene Elemente im Hauptfenster. Not enough free disk space available in: Nicht genügend freier Speicher verfügbar unter: @@ -506,10 +514,8 @@ Number of files that will be overwritten Anzahl der zu überschreibenden Dateien OK OK -Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the full name including path prefix. -Für die Synchronisation werden nur die Dateien/Verzeichnisse berücksichtigt, die den Filtereinstellungen entsprechen. Der Filter wird dabei auf den kompletten Dateinamen einschließlich Pfadprefix angewandt. -Open synchronization dialog -Synchronisationseinstellungen zeigen +Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the name relative(!) to the synchronization directories. +Für die Synchronisation werden nur die Dateien/Verzeichnisse berücksichtigt, die den Filtereinstellungen genügen. Der Filter wird dabei auf den Dateinamen relativ(!) zu den zu synchronisierenden Verzeichnissen angewandt. Open with File Manager\tD-Click Mit Dateimanager öffnen\tD-Click Operation aborted! @@ -530,6 +536,8 @@ Preview Vorschau Published under the GNU General Public License: Veröffentlicht unter der GNU General Public License: +Question +Frage Quit Beenden Relative path @@ -538,18 +546,20 @@ Remove folder pair Verzeichnispaar entfernen Reset Zurücksetzen +Reset all warning messages +Alle Warnmeldungen zurücksetzen Reset all warning messages? Sollen alle Warnmeldungen zurückgesetzt werden? -Resets all warning messages -Setzt alle Warnmeldungen zurück Result Ergebnis Right: Rechts: S&ave configuration Konfiguration s&peichern -Save aborted! -Speicherung abgebrochen! +S&witch view +Ansicht &wechseln +Save changes to current configuration? +Änderungen der aktuellen Konfiguration sichern? Save current configuration to file Aktuelle Konfiguration in Datei speichern Scanning... @@ -562,6 +572,10 @@ Select logfile directory: Verzeichnis für Logdatei wählen: Select variant: Variante auswählen: +Show conflicts +Konflikte zeigen +Show file icons +Zeige Dateisymbole Show files that are different Ungleiche Dateien anzeigen Show files that are equal @@ -574,6 +588,12 @@ Show files that exist on left side only Nur links existierende Dateien anzeigen Show files that exist on right side only Nur rechts existierende Dateien anzeigen +Show files that will be copied to the left side +Dateien die nach links kopiert werden anzeigen +Show files that will be copied to the right side +Dateien die nach rechts kopiert werden anzeigen +Show files that won't be copied +Dateien die nicht kopiert werden anzeigen Show popup Popup zeigen Show popup on errors or warnings @@ -598,6 +618,8 @@ Stop Stop Swap sides Seiten vertauschen +Synchronization Preview +Vorschau auf Synchronisation Synchronization aborted! Synchronisation abgebrochen! Synchronization completed successfully! @@ -610,7 +632,7 @@ Synchronization settings Synchronisationseinstellungen Synchronization status Synchronisationsstatus -Synchronize all .doc, .zip and .exe files except everything from folder \"temp\". +Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". Alle .doc, .zip und .exe Dateien mit Ausnahme des Verzeichnisses \"temp\" werden synchronisiert. Synchronize both sides simultaneously: Copy new or updated files in both directions. Beide Seiten gleichzeitig synchronisieren: Neue oder aktualisierte Dateien werden in beide Richtungen kopiert. @@ -638,6 +660,8 @@ Total required free disk space: Insgesamt benötigter freier Speicherplatz: Total time: Gesamtzeit: +Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes. +Betrachte Dateizeiten mit einer Differenz von genau +/- einer Stunde als gleich, mit weniger als einer Stunde als Konflikt, um Zeitumstellungen richtig zu behandeln. Two way <-> Beidseitig <-> Unable to connect to sourceforge.net! @@ -648,10 +672,10 @@ Unable to initialize Recycle Bin! Der Papierkorb konnte nicht initialisiert werden! Uncheck all Nichts auswählen +Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. +Es existieren ungelöste Konflikte! \n\nDie Konflikte können ignoriert und die Synchronisation fortgesetzt werden. Update -> Aktualisieren -> -Update: -Aktualisieren: Use Recycle Bin Papierkorb verwenden Use Recycle Bin when deleting or overwriting files during synchronization @@ -670,6 +694,8 @@ different verschieden file exists on both sides Datei existiert auf beiden Seiten +flash conflict\n +Blitz Konflikt\n on one side only nur auf einer Seite |> file on right side only\n diff --git a/Languages/hungarian.lng b/Languages/hungarian.lng index 78f11de6..5311e56b 100644 --- a/Languages/hungarian.lng +++ b/Languages/hungarian.lng @@ -10,14 +10,24 @@ PB TB TB + day(s) + + hour(s) + kB kB + min + + sec + != files are different\n != a fájlok különböznek\n %x directories %x könyvtár %x files, %x fájl, +%x is not a valid FreeFileSync batch file! + %x of %y rows in view %x sor látható a(z) %y sorból %x of 1 row in view @@ -32,8 +42,8 @@ &Alkalmaz &Cancel &Mégsem -&Compare -Öss&zehasonlítás +&Check for new version + &Create batch job &Kötegelt feladat létrehozása &Default @@ -54,6 +64,8 @@ &Betöltés &Load configuration &Beállítások betöltése +&No + &OK &OK &Pause @@ -64,16 +76,18 @@ &Ismét &Save &Mestés -&Start -&Indítás -&Synchronize... -&Szinkronizálás +&Yes + , . +- do not copy\n + +- conflict + +- conflict (same date, different size) + - different - különböző -- different (same date, different size) -- különböző (ugyanaz a dátum, eltérő méret) - equal - egyforma - exists left only @@ -88,26 +102,30 @@ - jobb oldali - right newer - a jobb oldali újabb -- same date (different size) -- ugyanaz a dátum (eltérő méret) +-> copy to right side\n + -Open-Source file synchronization- -Nyílt forráskódú fájlszinkronizálás- . , +/sec + 1 directory 1 könyvtár 1 file, 1 fájl, 1. &Compare 1. &Összehasonlítás -1. Enter full file or directory names separated by ';' or a new line. -1. Teljes fájl- vagy könyvtárnév megadása pontosvesszővel vagy új sorral elválasztva. +1. Enter relative file or directory names separated by ';' or a new line. + 2. &Synchronize... 2. &Szinkronizálás 2. Use wildcard characters '*' and '?'. 2. A csillag ('*') és a kérdőjel ('?') helyettesítő karakterek megengedettek. 3. Exclude files directly on main grid via context menu. 3. Fájlok közvetlen kizárása a fő listából helyi menü segítségével. +<- copy to left side\n + << left file is newer\n << a bal oldali fájl újabb\n <Directory> @@ -118,10 +136,12 @@ <többszörös kijelölés> <| file on left side only\n <| csak a bal oldalon lévő fájl\n -== files are equal\n\n -== a fájlok egyformák\n\n +== files are equal\n + >> right file is newer\n >> a jobb oldali fájl újabb\n +A newer version of FreeFileSync is available: + Abort requested: Waiting for current operation to finish... Megszakítási kérelem: Várakozás a folyamatban lévő művelet befejezésére... Aborted @@ -150,6 +170,8 @@ Batch job Kötegelt feladat Big thanks for localizing FreeFileSync goes out to: Nagy köszönet a FreeFileSync lokalizációjáért\na következő személyeknek: +Browse + Build: Build: Cancel @@ -160,6 +182,8 @@ Choose to hide filtered files/directories from list Szűrt fájlok/könyvtárak elrejése a listában Comma separated list Comma separated values +Compare + Compare both sides Mindkét oldal összehasonlítása Compare by \"File content\" @@ -172,8 +196,10 @@ Comparing content Tartalom összehasonlítása Comparing content of files %x %x fájlok tartalmának összehasonlítása -Comparing... -Összehasonlítás... +Comparing content... + +Comparison Result + Completed Befejezve Configuration @@ -210,12 +236,12 @@ Copy to clipboard\tCTRL+C Másolás a vágólapra\tCTRL+C Copying file %x to %y %x fájl másolása a(z) %y fájlba +Copying file %x to %y overwriting target + Could not set working directory: Munkakönyvtár beállítása sikertelen: Create a batch job Kötegelt feladat létrehozása -Create: -Létrehozás: Creating folder %x Könyvtár létrehozása %x Current operation: @@ -228,8 +254,6 @@ DECISION TREE DÖNTÉSI FA Data remaining: Hátralévő adat: -Data: -Adat: Date Dátum Delete files/folders existing on left side only @@ -242,16 +266,18 @@ Delete on both sides Törlés mindkét oldalon Delete on both sides even if the file is selected on one side only Törlés mindkét oldalon, még akkor is, ha csak egyik oldalon lett kijelölve -Delete: -Törlés: Deleting file %x Fájl törlése %x Deleting folder %x Könyvtár törlése %x Directories are dependent! Be careful when setting up synchronization rules: A könyvtárak függenek egymástól! Legyen óvatos, amikor megadja a szinkronizálási szabályokat: +Directory + Directory does not exist: A könyvtár nem létezik: +Do not display visual status information but write to a logfile instead + Do not show this warning again Ennek a figyelmeztetésnek az elrejtése legközelebb Do nothing @@ -260,10 +286,20 @@ Do you really want to delete the following objects(s)? Valóban törölni akarja a az alábbi objektumo(ka)t? Do you really want to move the following objects(s) to the Recycle Bin? Valóban a Lomtárba (Recycle Bin) akarja mozgatni az alábbi objektumo(ka)t? +Do you want FreeFileSync to automatically check for updates every week? + +Don't ask me again + Donate with PayPal Ha szereted a FreeFileSync-et, támogasd a PayPal segítségével. +Download now? + Drag && drop Húzd && Ejtsd +Email + +Enable filter to exclude files from synchronization + Error Hiba Error changing modification time: @@ -292,6 +328,8 @@ Error reading file: A fájl olvasása sikertelen: Error resolving symbolic link: A szimbolikus link feloldása sikertelen: +Error retrieving full path: + Error traversing directory: Könyvtár átnézése sikertelen: Error writing file attributes: @@ -316,6 +354,8 @@ Feedback and suggestions are welcome at: A visszajelzéseket és javaslatokat ide várjuk: File Manager integration: Beépülés a Fájlkezelőbe: +File Time tolerance (seconds): + File already exists. Overwrite? A fájl már létezik. Felülírjuk? File content @@ -338,8 +378,6 @@ Files remaining: Hátralévő fájlok: Files that exist on both sides and have different content Mindkét oldalon létező fájlok különböző tartalommal -Files that exist on both sides, have same date but different filesizes -Mindkét oldalon létező fájlok ugyanazzal a dátummal, de különböző mérettel Files that exist on both sides, left one is newer Mindkét oldalon létező fájlok, de a bal oldali újabb Files that exist on both sides, right one is newer @@ -352,6 +390,8 @@ Files/folders that exist on left side only Csak a bal oldalon létező fájlok/könyvtárak Files/folders that exist on right side only Csak a jobb oldalon létező fájlok/könyvtárak +Filter + Filter active: Press again to deactivate Szűrő aktív: Nyomja meg újra a deaktiváláshoz Filter files @@ -372,8 +412,10 @@ FreeFileSync batch file FreeFileSync kötegelt fájl FreeFileSync configuration FreeFileSync beállítások -Full name -Teljes név +FreeFileSync is up to date! + +Full path + Generating file list... Fájllista generálása... Global settings @@ -382,6 +424,8 @@ Help Súgó Hide all error and warning messages Összes hibaüzenet és figyelmeztetés elrejtése +Hide conflicts + Hide files that are different A nem egyező fájlok elrejtése Hide files that are equal @@ -394,6 +438,12 @@ Hide files that exist on left side only Csak a bal oldalon létező fájlok elrejtése Hide files that exist on right side only Csak a jobb oldalon létező fájlok elrejtése +Hide files that will be copied to the left side + +Hide files that will be copied to the right side + +Hide files that won't be copied + Hide filtered items A szűrt elemek elrejtése Hide further error messages during the current process @@ -402,8 +452,12 @@ Hides error messages during synchronization:\nThey are collected and shown as a Hibaüzenetek elrejtése szinkronizálás közben:\nÖssze lesznek gyűjtve és a folyamat végén meg lesznek jelenítve egy listában Hints: Tippek: +Homepage + If you like FFS FFS támogatása +Ignore 1-hour file time difference + Ignore errors Hibák figyelmen kívül hagyása Ignore subsequent errors @@ -416,8 +470,8 @@ Include Tartalmaz Include temporarily Ideiglenesen tartalmaz -Include: *.doc;*.zip;*.exe\nExclude: *\\temp\\* -Tartalmaz: *.doc;*.zip;*.exe\nKizárás: *\\temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\temp\\* + Info Információ Information @@ -426,24 +480,30 @@ Initialization of Recycle Bin failed! A Lomtár (Recycle Bin) inicializálása sikertelen! It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) Lehetetlen a Lomtár (Recycle Bin) inicializálása!\n\nValószínűleg azért, mert nem Windost használ.\nHa szeretné ezt a funkciót használni, kérjük, lépjen kapcsolatba a szerzővel. :) -Legend -Előzmény +Left: + Load configuration from file Beállítások betöltése fájlból Load configuration history (press DEL to delete items) Beállítások előzményeinek a betöltése (Nyomja meg a DEL gombot a törléshez) Log-messages: Naplóbejegyzések: +Logging + Mirror ->> Tükrözés ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. A bal oldali könyvtár tükrözött másolata: A jobb oldali könyvtár felülíródik és pontosan megegyezik majd a bal oldalival a szinkronizálás után. +More than 50% of the total number of files will be copied or deleted! + Move column down Oszlop mozgatása lefelé Move column up Oszlop mozgatása felfelé -Not all items were synchronized! Have a look at the list. -Nem minden elemet sikerült szinkronizálni. Vessen egy pillantást a listára. +Not all items have been synchronized! Have a look at the list. + +Not enough free disk space available in: + Nothing to synchronize according to configuration! A beállításoknak megfelelően nincs mit szinkronizálni! Number of files and directories that will be created @@ -454,18 +514,20 @@ Number of files that will be overwritten A felülírandó fájlok száma OK OK -Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the full name including path prefix. -Csak a szűrőnek megfelelő fájlok/könyvtárak lesznek kijelölve szinkronizáláshoz.\nA szűrő a teljes névre érvényes, amelybe beletartozik az útvonal is. -Open synchronization dialog -Szinkronizációs ablak megnyitása +Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the name relative(!) to the synchronization directories. + Open with File Manager\tD-Click Megnyitás a Fájlkezelőben\tD-Click Operation aborted! Művelet megszakítva! Operation: Művelet: +Overview + Pause Szünet +Paused + Please fill all empty directory fields. Kérjük, töltse ki az összes üres könyvtár mezőt. Press button to activate filter @@ -474,6 +536,8 @@ Preview Előnézet Published under the GNU General Public License: Kiadva a GNU General Public License alatt: +Question + Quit Kilépés Relative path @@ -482,16 +546,20 @@ Remove folder pair Könyvtár párok eltávolítása Reset Helyreállítás +Reset all warning messages + Reset all warning messages? Helyreállítja az összes figyelmeztető üzenetet? -Resets all warning messages -Az összes figyelmeztető üzenet helyreállítása Result Eredmény +Right: + S&ave configuration Beállítások mentés&e -Save aborted! -Mentés megszakítva! +S&witch view + +Save changes to current configuration? + Save current configuration to file Aktuális beállítások mentése fájlba Scanning... @@ -500,8 +568,14 @@ Scanning: Vizsgálat: Select a folder Könyvtár kiválasztása +Select logfile directory: + Select variant: Változat kiválasztása: +Show conflicts + +Show file icons + Show files that are different Eltérő fájlok mutatása Show files that are equal @@ -514,10 +588,18 @@ Show files that exist on left side only Csak a bal oldalon létező fájlok mutatása Show files that exist on right side only Csak a jobb oldalon létező fájlok mutatása +Show files that will be copied to the left side + +Show files that will be copied to the right side + +Show files that won't be copied + Show popup Felbukkanó ablak mutatása Show popup on errors or warnings Értesítés felbukkanó ablakban a hibákról és figyelmeztetésekről +Significant difference detected: + Silent mode Csendes mód Size @@ -526,6 +608,8 @@ Sorting file list... Fájllista rendezése... Source code written completely in C++ utilizing: A forráskód teljes egészében C++-ban íródott\na következők felhasználásával: +Speed: + Start Indítás Start synchronization @@ -534,6 +618,8 @@ Stop Megállítás Swap sides Oldalak felcserélése +Synchronization Preview + Synchronization aborted! A szinkronizáció megszakítva! Synchronization completed successfully! @@ -546,8 +632,8 @@ Synchronization settings Szinkronizáció beállításai Synchronization status Szinkronizáció állapota -Synchronize all .doc, .zip and .exe files except everything from folder \"temp\". -Minden .doc, .zip és .exe fájl szinkronizálása a \"temp\" könyvtárban levők kivételével. +Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". + Synchronize both sides simultaneously: Copy new or updated files in both directions. Mindkét oldal szinkronizálása egyszerre: Új és frissített fájlok másolása mindkét irányban. Synchronizing... @@ -566,22 +652,30 @@ Time Idő Time elapsed: Eltelt idő: +Time remaining: + Total amount of data that will be transferred A mozgatandó adatok összmérete +Total required free disk space: + Total time: Becsült idő: +Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes. + Two way <-> Kétirányú <-> +Unable to connect to sourceforge.net! + Unable to create logfile! Nem lehet létrehozni a naplófájlt! Unable to initialize Recycle Bin! Nem lehet inicializálni a Lomtárat (Recycle Bin)! Uncheck all Összes kijelölést megszűntet +Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. + Update -> Frissítés -> -Update: -Frissítés: Use Recycle Bin Lomtár (Recycle Bin) használata Use Recycle Bin when deleting or overwriting files during synchronization @@ -600,6 +694,8 @@ different különböző file exists on both sides mindkét oldalon létező fájlok +flash conflict\n + on one side only csak az egy oldalon létező fájlok |> file on right side only\n diff --git a/Languages/italian.lng b/Languages/italian.lng index 6ebfab73..207294c4 100644 --- a/Languages/italian.lng +++ b/Languages/italian.lng @@ -10,14 +10,24 @@ PB TB TB + day(s) + giorno(i) + hour(s) + ora(e) kB kB + min + min + sec + sec != files are different\n != i file sono diversi\n %x directories %x cartelle %x files, %x files, +%x is not a valid FreeFileSync batch file! +%x non è un batch file valido per FreeFileSync! %x of %y rows in view %x di %y righe visualizzate %x of 1 row in view @@ -32,8 +42,8 @@ &Applica &Cancel &Annulla -&Compare -&Compara +&Check for new version +&Controlla la presenza di nuove versioni &Create batch job &Crea un job in batch &Default @@ -54,6 +64,8 @@ &Carica &Load configuration &Carica la configurazione +&No +&No &OK &OK &Pause @@ -64,16 +76,18 @@ &Riprova &Save &Salva -&Start -&Avvia -&Synchronize... -&Sincronizzazione... +&Yes +&Si , , +- do not copy\n +- non copiare\n +- conflict +- conflitto +- conflict (same date, different size) +- conflitto (stessa data, dimensione diversa) - different - file diversi -- different (same date, different size) -- file diversi (stessa data, diversa dimensione) - equal - file identici - exists left only @@ -88,26 +102,30 @@ - a destra - right newer - file di destra più recente -- same date (different size) -- stessa data (diversa dimensione) +-> copy to right side\n +-> copia sul lato destro\n -Open-Source file synchronization- -Sincronizzazione Open-Source- . , +/sec +/sec 1 directory 1 directory 1 file, 1 file, 1. &Compare 1. &Compara -1. Enter full file or directory names separated by ';' or a new line. -1. Inserisci il nome completo dei file o delle directory separati da ';' o da un 'a capo'. +1. Enter relative file or directory names separated by ';' or a new line. +1. Inserisci i nomi relativi di file o directory separati da ';' o su una nuova riga. 2. &Synchronize... 2. &Sincronizza... 2. Use wildcard characters '*' and '?'. 2. Sono ammessi i caratteri generici '*' e '?'. 3. Exclude files directly on main grid via context menu. -3. Escludi i file direttamente sul main grid tramite il menu contestuale. +3. Escludi i file direttamente sulla griglia principale tramite il menu contestuale. +<- copy to left side\n +<- copia sul lato sinistro\n << left file is newer\n << il file di sinistra è più recente\n <Directory> @@ -118,10 +136,12 @@ <selezione multipla> <| file on left side only\n <| il file esiste solo a sinistra\n -== files are equal\n\n -== i file sono identici\n\n +== files are equal\n +== i file sono uguali\n >> right file is newer\n >> il file di destra è più recente\n +A newer version of FreeFileSync is available: +E' disponibile una nuova versione di FreeFileSync: Abort requested: Waiting for current operation to finish... Abbandono richiesto: in attesa della fine dell'operazione in corso... Aborted @@ -150,6 +170,8 @@ Batch job Batch job Big thanks for localizing FreeFileSync goes out to: Per la traduzione di FreeFileSync, un grazie va a: +Browse +Sfoglia Build: Build: Cancel @@ -160,6 +182,8 @@ Choose to hide filtered files/directories from list Nascondi i files/directories dalla lista Comma separated list Lista di elementi separati da virgola +Compare +Compara Compare both sides Compara le due liste Compare by \"File content\" @@ -172,8 +196,10 @@ Comparing content Comparazione contenuto Comparing content of files %x Comparazione contenuto del file %x -Comparing... -Comparazione in corso... +Comparing content... +Comparazione contenuto... +Comparison Result +Risultato della comparazione Completed Completato Configuration @@ -210,12 +236,12 @@ Copy to clipboard\tCTRL+C Copia nella clipboard\tCTRL+C Copying file %x to %y Copia di file da %x a %y +Copying file %x to %y overwriting target +Copia file %x su %y sovrascrivendo la destinazione Could not set working directory: Impossibile definire la directory di lavoro: Create a batch job Creazione di un job batch -Create: -Crea: Creating folder %x Creazione cartella %x Current operation: @@ -228,8 +254,6 @@ DECISION TREE ALBERO DELLE DECISIONI Data remaining: Dati rimanenti: -Data: -Dati: Date Data Delete files/folders existing on left side only @@ -242,16 +266,18 @@ Delete on both sides Cancella su entrambi i lati Delete on both sides even if the file is selected on one side only Cancella su entrambi i lati anche se il file è selezionato su un solo lato. -Delete: -Elimina: Deleting file %x Eliminazione file %x Deleting folder %x Eliminazione cartella %x Directories are dependent! Be careful when setting up synchronization rules: Le directory sono dipendenti! Fai attenzione quando configuri le regole di sincronizzazione: +Directory +Directory Directory does not exist: La directory non esiste: +Do not display visual status information but write to a logfile instead +Non visualizzare le informazioni di stato ma scrivile in un file di log Do not show this warning again Non mostrare più questo messaggio Do nothing @@ -260,10 +286,20 @@ Do you really want to delete the following objects(s)? Vuoi veramente eliminare i seguenti oggetti? Do you really want to move the following objects(s) to the Recycle Bin? Vuoi veramente spostare i seguenti oggetti nel Cestino? +Do you want FreeFileSync to automatically check for updates every week? +Vuoi che FreeFileSync controlli automaticamente gli aggiornamenti ogni settimana? +Don't ask me again +Non chiederlo di nuovo Donate with PayPal Fai una donazione con PayPal +Download now? +Scaricare ora? Drag && drop Drag && drop +Email +Email +Enable filter to exclude files from synchronization +Abilita il filtro per escludere files dalla sincronizzazione Error Errore Error changing modification time: @@ -292,6 +328,8 @@ Error reading file: Errore durante la lettura del file: Error resolving symbolic link: Errore nella risoluzione di collegamento simbolico: +Error retrieving full path: +Errore nel reperire il percorso completo: Error traversing directory: Errore nel percorso della directory: Error writing file attributes: @@ -316,6 +354,8 @@ Feedback and suggestions are welcome at: Commenti e suggerimenti sono i benvenuti: File Manager integration: Integrazione File Manager: +File Time tolerance (seconds): +Tolleranza di File Time (in secondi): File already exists. Overwrite? Il file esiste già. Lo vuoi sovrascrivere? File content @@ -338,8 +378,6 @@ Files remaining: File rimanenti: Files that exist on both sides and have different content Files esistenti su entrambi i lati e aventi differente contenuto -Files that exist on both sides, have same date but different filesizes -Files esistenti su entrambi i lati e aventi la stessa data ma dimensioni differenti Files that exist on both sides, left one is newer Files esistenti su entrambi i lati, più recenti a sinistra Files that exist on both sides, right one is newer @@ -352,6 +390,8 @@ Files/folders that exist on left side only Files/cartelle esistenti solo a sinistra Files/folders that exist on right side only Files/cartelle esistenti solo a destra +Filter +Filtro Filter active: Press again to deactivate Filtro attivo: Clicca nuovamente per disattivare Filter files @@ -372,8 +412,10 @@ FreeFileSync batch file FreeFileSync batch file FreeFileSync configuration FreeFileSync configurazione -Full name -Nome completo +FreeFileSync is up to date! +FreeFileSync è aggiornato! +Full path +Percorso completo Generating file list... Generazione lista dei file... Global settings @@ -382,6 +424,8 @@ Help Aiuto Hide all error and warning messages Nascondi tutti gli errori e i messaggi d'avviso +Hide conflicts +Nascondi i conflitti Hide files that are different Nascondi i file differenti Hide files that are equal @@ -394,6 +438,12 @@ Hide files that exist on left side only Nascondi i file esistenti solo a sinistra Hide files that exist on right side only Nascondi i file esistenti solo a destra +Hide files that will be copied to the left side +Nascondi i file da copiare sul lato sinistro +Hide files that will be copied to the right side +Nascondi i file da copiare sul lato destro +Hide files that won't be copied +Nascondi i file che non saranno copiati Hide filtered items Nascondi gli elementi filtrati Hide further error messages during the current process @@ -402,8 +452,12 @@ Hides error messages during synchronization:\nThey are collected and shown as a Non mostrare i messaggi d'errore durante la sincronizzazione:\nVerranno raccolti e mostrati alla fine del processo Hints: Consigli: +Homepage +Homepage If you like FFS Se ti piace FFS +Ignore 1-hour file time difference +Ignora la differenza di file time di 1 ora Ignore errors Ignora gli errori Ignore subsequent errors @@ -416,8 +470,8 @@ Include Includi Include temporarily Includi temporaneamente -Include: *.doc;*.zip;*.exe\nExclude: *\\temp\\* -Includi: *.doc;*.zip;*.exe\nEscludi: *\\temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\temp\\* +Includi: *.doc;*.zip;*.exe\nEscludi: \\temp\\* Info Info Information @@ -426,24 +480,30 @@ Initialization of Recycle Bin failed! Inizializzazione del Cestino fallita! It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) Impossibile inizializzare il Cestino!\n\nE'probabile che non si stia utilizzando Windows.\nSe si vuole usare questa funzionalità, contattare l'autore. :) -Legend -Legenda +Left: +Sinistra: Load configuration from file Carica configurazione da file Load configuration history (press DEL to delete items) Carica la cronologia delle configurazioni (premi DEL per eliminare elementi) Log-messages: Log-messages: +Logging +Logging Mirror ->> Mirror ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Mirror backup della cartella di sinistra: La cartella di destra sarà sovrascritta e resa identica alla cartella di sinistra dopo la sincronizzazione. +More than 50% of the total number of files will be copied or deleted! +Piu' del 50% del totale dei files saranno copiati o cancellati! Move column down Sposta colonna giu' Move column up Sposta colonna su' -Not all items were synchronized! Have a look at the list. -Alcuni elementi non sono stati sincronizzati! Controllare la lista. +Not all items have been synchronized! Have a look at the list. +Non tutti gli oggetti sono stati sincronizzati! Controlla la lista. +Not enough free disk space available in: +Spazio libero su disco non sufficiente in: Nothing to synchronize according to configuration! Niente da sincronizzare in questa configurazione! Number of files and directories that will be created @@ -454,18 +514,20 @@ Number of files that will be overwritten Numero di file che verranno sovrascritti OK OK -Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the full name including path prefix. -Solo i files/cartelle filtrati saranno selezionati per la sincronizzazione. Il filtro verrà applicato al nome completo incluso il percorso. -Open synchronization dialog -Apri la finestra di dialogo della sincronizzazione +Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the name relative(!) to the synchronization directories. +Solo file e/o directory non filtrati saranno selezionati per la sincronizzazione. Il filtro verrà applicato al nome relativo(!) nelle directory di sincronizzazione. Open with File Manager\tD-Click Apri con File Manager\tD-Click Operation aborted! Operazione abortita! Operation: Operazione: +Overview +Controllo generale Pause Pausa +Paused +In pausa Please fill all empty directory fields. Compilare tutti i campi di directory vuoti. Press button to activate filter @@ -474,6 +536,8 @@ Preview Anteprima Published under the GNU General Public License: Pubblicato sotto licenza GNU General Public: +Question +Domanda Quit Esci Relative path @@ -482,16 +546,20 @@ Remove folder pair Elimina la coppia di cartelle Reset Reset +Reset all warning messages +Resetta tutti i messaggi d'avviso Reset all warning messages? -Resettare tutti gli avvisi? -Resets all warning messages -Resetta tutti gli avvisi +Resettare tutti i messaggi d'avviso? Result Risultato +Right: +Destra: S&ave configuration S&alva la configurazione -Save aborted! -Salvataggio abortito! +S&witch view +C&ommuta vista +Save changes to current configuration? +Salvare i cambiamenti alla configurazione corrente? Save current configuration to file Salva su file la configurazione corrente Scanning... @@ -500,8 +568,14 @@ Scanning: Analisi in corso: Select a folder Selezionare una cartella +Select logfile directory: +Seleziona cartella per il file di log: Select variant: Selezionare una variante: +Show conflicts +Mostra conflitti +Show file icons +Mostra icone dei file Show files that are different Mostra file differenti Show files that are equal @@ -514,10 +588,18 @@ Show files that exist on left side only Mostra file esistenti solo a sinistra Show files that exist on right side only Mostra file esistenti solo a destra +Show files that will be copied to the left side +Mostra file da copiare sul lato sinistro +Show files that will be copied to the right side +Mostra file da copiare sul lato destro +Show files that won't be copied +Mostra file che non saranno copiati Show popup Mostra popup Show popup on errors or warnings Mostra popup degli errori o avvisi +Significant difference detected: +Riscontrate differenze significative: Silent mode Modalità Silenziosa Size @@ -526,6 +608,8 @@ Sorting file list... Ordinamento lista file... Source code written completely in C++ utilizing: Codice sorgente scritto completamente in C++ \ne utilizzando: +Speed: +Velocita': Start Avvia Start synchronization @@ -534,6 +618,8 @@ Stop Stop Swap sides Inverti i lati +Synchronization Preview +Anteprima Sincronizzazione Synchronization aborted! Sincronizzazione abortita! Synchronization completed successfully! @@ -546,8 +632,8 @@ Synchronization settings Parametri di sincronizzazione Synchronization status Stato della sincronizzazione -Synchronize all .doc, .zip and .exe files except everything from folder \"temp\". -Sincronizza tutti i file .doc, .zip e .exe eccetto la cartella \"temp\". +Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". +Sincronizza tutti i file .doc, .zip e .exe eccetto tutti quelli nella cartella \"temp\". Synchronize both sides simultaneously: Copy new or updated files in both directions. Sincronizza simultaneamente entrambi i lati: Copia file nuovi o aggiornati in entrambe le direzioni. Synchronizing... @@ -566,22 +652,30 @@ Time Ora Time elapsed: Tempo trascorso: +Time remaining: +Tempo rimanente: Total amount of data that will be transferred Volume dei dati che verranno trasferiti +Total required free disk space: +Spazio libero su disco richiesto: Total time: Tempo totale: +Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes. +Tratta file time che differiscono di esattamente +/- 1 ora come uguali, meno di 1 ora come conflitto per gestire i cambiamenti di Daylight Saving Time. Two way <-> Dai 2 lati <-> +Unable to connect to sourceforge.net! +Impossibile collegarsi a sourceforge.net! Unable to create logfile! Impossibile creaer il file di log! Unable to initialize Recycle Bin! Impossibile inizializzare il Cestino! Uncheck all Deseleziona tutto +Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. +Sono presenti conflitti irrisolti! \n\nPuoi ignorare i conflitti e continuare la sincronizzazione. Update -> Aggiorna -> -Update: -Aggiorna: Use Recycle Bin Usa il Cestino Use Recycle Bin when deleting or overwriting files during synchronization @@ -600,6 +694,8 @@ different file differenti file exists on both sides file esistente su entrambi i lati +flash conflict\n +conflitto flash\n on one side only file esistente su un solo lato |> file on right side only\n diff --git a/Languages/japanese.lng b/Languages/japanese.lng index 5f80339f..ae591d05 100644 --- a/Languages/japanese.lng +++ b/Languages/japanese.lng @@ -44,8 +44,6 @@ キャンセル(&C) &Check for new version バージョン更新の確認(&C) -&Compare -比較(&C) &Create batch job 一括ジョブを作成(&C) &Default @@ -66,6 +64,8 @@ 読み込み(&L) &Load configuration 構成設定の読み込み(&L) +&No +いいえ(&N) &OK &OK &Pause @@ -76,16 +76,18 @@ 再試行(&R) &Save 保存(&S) -&Start -開始(&S) -&Synchronize... -同期(&S)... +&Yes +はい(&Y) , . +- do not copy\n +- コピーしない\n +- conflict +- 不一致 +- conflict (same date, different size) +- 不一致 (同じ日付, 異なるサイズ) - different - 差異あり -- different (same date, different size) -- 差異あり(日付は同一、サイズが異なります) - equal - 同一 - exists left only @@ -100,8 +102,8 @@ - 右側 - right newer - 右側の方が新しい -- same date (different size) -- 日付は同一(サイズに差異あり) +-> copy to right side\n +-> 右側にコピー\n -Open-Source file synchronization- -Open-Source ファイル同期ツール- . @@ -114,16 +116,16 @@ 1 ファイル 1. &Compare 1. 比較(&C) -1. Enter full file or directory names separated by ';' or a new line. -1. 完全なファイル/ディレクトリ名を ' ; ' で区切って入力してください。 +1. Enter relative file or directory names separated by ';' or a new line. +1. 相対ファイル、またはディレクトリを ';' または 改行で区切って入力 2. &Synchronize... 2. 同期処理(&S)... 2. Use wildcard characters '*' and '?'. 2. ワイルドカードに ' * ' と ' ? ' を使用出来ます。 3. Exclude files directly on main grid via context menu. 3. コンテキストメニューから直接ファイルを除外出来ます。 -4. Keep the number of (different) entries small for best performance. -4. 保持エントリ数を小さい値にすることで、より最適な性能を発揮します。 +<- copy to left side\n +<- 左側にコピー\n << left file is newer\n << 左側の方が新しい\n <Directory> @@ -134,8 +136,8 @@ <複数選択> <| file on left side only\n <| 左側のみに存在\n -== files are equal\n\n -== 同じ内容のファイル\n\n +== files are equal\n +== 同様のファイル\n >> right file is newer\n >> 右側の方が新しい\n A newer version of FreeFileSync is available: @@ -157,9 +159,9 @@ An exception occured! As a result the files are separated into the following categories: ファイルは以下のカテゴリに分類されます: As the name suggests, two files which share the same name are marked as equal if and only if they have the same content. This option is useful for consistency checks rather than backup operations. Therefore the file times are not taken into account at all.\n\nWith this option enabled the decision tree is smaller: -このオプションでは、同じ名前を共有するファイルで内容が同じ場合は、同一として扱われます。 バックアップ操作より、むしろ整合性のチェックを行う時に役立つオプションです。 従ってファイルの日時については全く考慮されていません。\n\n設定が有効な時は、ツリー表示が小さくなります。 +このオプションでは、同じ名前を共有するファイルで内容が同じ場合は、同一として扱われます。 バックアップ操作より、むしろ整合性のチェックを行う時に役立つオプションです。 従ってファイルの日時については全く考慮されていません。\n\n設定が有効な時は、ツリー表示が小さくなります。 Assemble a batch file for automated synchronization. To start in batch mode simply pass the name of the file to the FreeFileSync executable: FreeFileSync.exe <batchfile>. This can also be scheduled in your operating system's task planner. -一括で同期処理を行うためのバッチファイルを作成します。一括モードを開始するときは、ファイルのパス名を実行ファイル\n< FreeFileSync.exe> \nにバッチファイルで渡すだけです。また、この操作はOSのタスクスケジューラから実行することができます。 +一括で同期処理を行うためのバッチファイルを作成します。 一括モードを開始するときは、ファイルのパス名を実行ファイル\n< FreeFileSync.exe> \nにバッチファイルで渡すだけです。 また、この操作はOSのタスクスケジューラから実行することができます。 Batch execution 一括処理を実行 Batch file created successfully! @@ -168,6 +170,8 @@ Batch job 一括処理 Big thanks for localizing FreeFileSync goes out to: FreeFileSync のローカライズへの協力に感謝します: +Browse +参照 Build: ビルド: Cancel @@ -178,6 +182,8 @@ Choose to hide filtered files/directories from list リストから除外したいファイル/ディレクトリを選択 Comma separated list カンマ区切り +Compare +比較 Compare both sides 両方を比較 Compare by \"File content\" @@ -190,8 +196,10 @@ Comparing content 内容の比較中 Comparing content of files %x ファイル %x の内容を比較中 -Comparing... -比較中... +Comparing content... +内容を比較中... +Comparison Result +比較結果 Completed 完了しました Configuration @@ -234,8 +242,6 @@ Could not set working directory: 作業ディレクトリが設定できません: Create a batch job 一括ジョブを作成 -Create: -作成: Creating folder %x フォルダ %x を作成中 Current operation: @@ -248,8 +254,6 @@ DECISION TREE [判定ツリー] Data remaining: 残りのデータ: -Data: -データ: Date データ Delete files/folders existing on left side only @@ -262,8 +266,6 @@ Delete on both sides 両方を削除 Delete on both sides even if the file is selected on one side only 片側のペインのみ選択されている場合でも両方を削除する -Delete: -削除: Deleting file %x ファイル %x を削除中 Deleting folder %x @@ -286,6 +288,8 @@ Do you really want to move the following objects(s) to the Recycle Bin? 本当に以下のオブジェクト(複)をゴミ箱に移動しますか? Do you want FreeFileSync to automatically check for updates every week? FreeFileSync のアップデートの有無の確認を自動的に毎週行いますか> +Don't ask me again +次回から確認しない Donate with PayPal PayPal から寄付する Download now? @@ -374,8 +378,6 @@ Files remaining: 残りのファイル: Files that exist on both sides and have different content 両側に存在するが、内容が異なるファイル -Files that exist on both sides, have same date but different filesizes -両側に存在して、日付は同じだが、ファイルサイズが異なるファイル Files that exist on both sides, left one is newer 両側に存在するが、左側の方がより新しい Files that exist on both sides, right one is newer @@ -412,8 +414,8 @@ FreeFileSync configuration FreeFileSync 構成設定 FreeFileSync is up to date! FreeFileSync は最新です! -Full name -完全な名前 +Full path +フルパス Generating file list... ファイル一覧を作成中... Global settings @@ -422,6 +424,8 @@ Help ヘルプ Hide all error and warning messages すべてのエラーと警告メッセージを非表示 +Hide conflicts +不一致を隠す Hide files that are different 異なるファイルを非表示 Hide files that are equal @@ -434,6 +438,12 @@ Hide files that exist on left side only 左側のみに存在するファイルを非表示 Hide files that exist on right side only 右側のみに存在するファイルを非表示 +Hide files that will be copied to the left side +左側にコピーしたファイルを非表示にする +Hide files that will be copied to the right side +右側にコピーしたファイルを非表示にする +Hide files that won't be copied +コピーしなかったファイルを隠す Hide filtered items 適合するアイテムを非表示にする Hide further error messages during the current process @@ -446,6 +456,8 @@ Homepage ホームページ If you like FFS FFS が気に入った場合 +Ignore 1-hour file time difference +1 時間のファイル時間の差異は無視 Ignore errors エラーを無視 Ignore subsequent errors @@ -458,8 +470,8 @@ Include 含める Include temporarily 一時フォルダを含める -Include: *.doc;*.zip;*.exe\nExclude: *\\temp\\* -含める: *.doc;*.zip;*.exe\n除外: *\\temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\temp\\* +含める: *.doc;*.zip;*.exe\n除外: \\temp\\* Info 情報 Information @@ -470,8 +482,6 @@ It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are n ゴミ箱を初期化することが出来ませんでした!\n\n使用している OS が、Windows 以外の OS です。\nこの機能を使用したい場合は、作者までご連絡ください :) Left: 左側: -Legend -履歴 Load configuration from file 外部ファイルから構成設定を読み込みます Load configuration history (press DEL to delete items) @@ -490,8 +500,8 @@ Move column down 列を下に移動 Move column up 列を上に移動 -Not all items were synchronized! Have a look at the list. -すべてのアイテムは同期されていません! 詳細はリストをご覧ください。 +Not all items have been synchronized! Have a look at the list. +すべてのアイテムは同期されていません、リストを確認してください Not enough free disk space available in: 利用可能なディスク空き容量が足りません: Nothing to synchronize according to configuration! @@ -504,10 +514,8 @@ Number of files that will be overwritten 上書きされたファイル数 OK OK -Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the full name including path prefix. -選択されたファイル/ディレクトリを同期処理する時だけフィルタリングされます。\nこのフィルターは、接頭語を含むパスと完全な名前にのみ適用されます。 -Open synchronization dialog -同期ダイアログを開く +Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the name relative(!) to the synchronization directories. +フィルタリングをパスしたファイル/ディレクトリのみが同期対象に選択されます。 フィルターは同期先ディレクトリの同類の名前(!)に対して適用されます。 Open with File Manager\tD-Click ファイラーから開く\tD-クリック Operation aborted! @@ -528,6 +536,8 @@ Preview プレビュー Published under the GNU General Public License: Published under the GNU General Public License: +Question +質問 Quit 終了 Relative path @@ -536,18 +546,20 @@ Remove folder pair フォルダペアを除去 Reset リセット +Reset all warning messages +すべての警告をリセット Reset all warning messages? すべての警告をリセットしますか? -Resets all warning messages -すべての警告をリセット Result 結果 Right: 右側: S&ave configuration 構成設定を保存(&A) -Save aborted! -保存を中断! +S&witch view +表示切り替え(&W) +Save changes to current configuration? +現在の構成の変更を保存しますか? Save current configuration to file 現在の設定をファイルに保存 Scanning... @@ -560,6 +572,10 @@ Select logfile directory: ログファイルの保存先を選択: Select variant: 変数を選択: +Show conflicts +不一致を表示 +Show file icons +アイコンを表示 Show files that are different 差異のあるファイルを表示 Show files that are equal @@ -572,6 +588,12 @@ Show files that exist on left side only 左側のみに存在するファイルを表示 Show files that exist on right side only 右側のみに存在するファイルを表示 +Show files that will be copied to the left side +左側にコピーされたファイルを表示 +Show files that will be copied to the right side +右側にコピーされたファイルを表示 +Show files that won't be copied +コピーされなかったファイルを表示 Show popup ポップアップ表示 Show popup on errors or warnings @@ -596,6 +618,8 @@ Stop 停止 Swap sides パネルを入れ替え +Synchronization Preview +同期処理のプレビュー Synchronization aborted! 同期処理を中断! Synchronization completed successfully! @@ -608,8 +632,8 @@ Synchronization settings 同期処理設定 Synchronization status 同期処理: ステータス -Synchronize all .doc, .zip and .exe files except everything from folder \"temp\". -.doc, .zip and .exe ファイル以外を \"temp\" フォルダからすべて同期 +Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". +\"temp\" のサブフォルダを除いて、すべての.doc、.zip、および.exeファイルを同期 Synchronize both sides simultaneously: Copy new or updated files in both directions. 両側を同時に処理: 両方のディレクトリのより新しいファイルをコピー Synchronizing... @@ -621,7 +645,7 @@ Target file already existing! The file does not contain a valid configuration: このファイルには有効な構成が含まれていません: This commandline will be executed each time you doubleclick on a filename. %name serves as a placeholder for the selected file. -ファイル名をダブルクリックする度に、このコマンドが実行されます。%name は選択ファイルのプレースフォルダとして機能します。 +ファイル名をダブルクリックする度に、このコマンドが実行されます。 %name は選択ファイルのプレースフォルダとして機能します。 This variant evaluates two equally named files as being equal when they have the same file size AND the same last write date and time. この変数では、ふたつの同名ファイルが存在した場合、 それぞれのファイルサイズと最終更新日付/時間を比較します。 Time @@ -636,6 +660,8 @@ Total required free disk space: 必要な合計ディスク空き容量: Total time: 合計時間: +Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes. +ファイルの時間の +/- を正確に 1 時間以上の差異は不一致、1 時間未満の差異は同様ファイルとして取り扱います(夏時間は変換されます) Two way <-> 両方向 <-> Unable to connect to sourceforge.net! @@ -646,10 +672,10 @@ Unable to initialize Recycle Bin! ゴミ箱の初期化が出来ません! Uncheck all すべて解除 +Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. +未解決の不一致があります! \n\nこの不一致を無視して同期を続行することが出来ます。 Update -> 更新 -> -Update: -アップデート: Use Recycle Bin ゴミ箱を使用 Use Recycle Bin when deleting or overwriting files during synchronization @@ -668,6 +694,8 @@ different 差異あり file exists on both sides 両側に存在するファイル +flash conflict\n +不一致を点滅 on one side only 片側のみ |> file on right side only\n diff --git a/Languages/polish.lng b/Languages/polish.lng index c46cf4b0..324542c9 100644 --- a/Languages/polish.lng +++ b/Languages/polish.lng @@ -44,8 +44,6 @@ &Anuluj &Check for new version &Sprawdź aktualizacje -&Compare -&Porównaj &Create batch job &Twórz zadanie batch &Default @@ -66,6 +64,8 @@ &Wczytaj &Load configuration &Ładuj konfigurację +&No +&Nie &OK &OK &Pause @@ -76,16 +76,18 @@ &Powtórz &Save &Zapisz -&Start -&Start -&Synchronize... -&Synchronizuj... +&Yes +&Tak , . +- do not copy\n +- nie kopiuj\n +- conflict +- konflikt +- conflict (same date, different size) +- konflikt (ta sama data, różny rozmiar) - different - różny -- different (same date, different size) -- różnica (jednakowa data, różny rozmiar) - equal - równy - exists left only @@ -100,8 +102,8 @@ - prawy - right newer - prawy jest nowszy -- same date (different size) -- jednakowa data (różny rozmiar) +-> copy to right side\n +-> kopiuj na prawą stronę -Open-Source file synchronization- -synchronizacja plików Open-Source- . @@ -114,16 +116,16 @@ 1 plik, 1. &Compare 1. &Porównaj -1. Enter full file or directory names separated by ';' or a new line. -1. Wprowadź pełne ścieżki do plików lub katalogów oddzielone ';' albo nową linią. +1. Enter relative file or directory names separated by ';' or a new line. +1. Wprowdź relatywne scieżki do plików lub katalogów oddzielone ';' lub nową linią. 2. &Synchronize... 2. &Synchronizuj... 2. Use wildcard characters '*' and '?'. 2. Użyj wieloznacznika (wildcard) '*' i '?'. 3. Exclude files directly on main grid via context menu. 3. Wyklucz pliki i foldery używając prawego przycisku myszki. -4. Keep the number of (different) entries small for best performance. -4. Przechowuj małą liczbę wpisów (różnych) dla lepszej wydajności. +<- copy to left side\n +<- kopiuje na lewą stronę\n << left file is newer\n << lewy plik jest nowszy\n <Directory> @@ -134,8 +136,8 @@ <zaznaczone elementy> <| file on left side only\n <| istnieje tylko po lewej stronie\n -== files are equal\n\n -== pliki są równe\n\n +== files are equal\n +== pliki są równe\n >> right file is newer\n >> prawy plik jest nowszy\n A newer version of FreeFileSync is available: @@ -168,6 +170,8 @@ Batch job Zadanie batch Big thanks for localizing FreeFileSync goes out to: Podziękowania za tłumaczenie FreeFileSync: +Browse +Przeglądaj Build: Buduj: Cancel @@ -178,6 +182,8 @@ Choose to hide filtered files/directories from list Zaznacz aby ukryć przefiltrowane pliki/katalogi z listy Comma separated list Lista oddzielona przecinkami +Compare +Porównaj Compare both sides Porównaj foldery Compare by \"File content\" @@ -190,8 +196,10 @@ Comparing content Porównuję zawartość Comparing content of files %x Porównywanie zawartości plików %x -Comparing... -Porównuje... +Comparing content... +Porównywanie zawartości... +Comparison Result +Rezultat porównywania Completed Zakończono Configuration @@ -234,8 +242,6 @@ Could not set working directory: Nie można ustawić poprawnego folderu: Create a batch job Twórz zadanie Batch -Create: -Utwórz: Creating folder %x Tworzenie folderu %x Current operation: @@ -248,8 +254,6 @@ DECISION TREE DRZEWO DECYZYJNE Data remaining: Pozostałe dane: -Data: -Dane: Date Data Delete files/folders existing on left side only @@ -262,8 +266,6 @@ Delete on both sides Usuń po obu stronach Delete on both sides even if the file is selected on one side only Usuń po obu stronach nawet jeżeli plik zaznaczony jest tylko po jednej stronie -Delete: -Usuń: Deleting file %x Usuwanie pliku %x Deleting folder %x @@ -286,6 +288,8 @@ Do you really want to move the following objects(s) to the Recycle Bin? Czy na pewno chcesz przenieść wybrane pliki do kosza? Do you want FreeFileSync to automatically check for updates every week? Czy chcesz aby FreeFileSync sprawdzał uaktualnienia co tydzień? +Don't ask me again +Nie pytaj mnie ponownie Donate with PayPal Wesprzyj z PayPal Download now? @@ -374,8 +378,6 @@ Files remaining: Pozostałe pliki: Files that exist on both sides and have different content Pliki, które istnieją po obu stronach i różnią się zawartością -Files that exist on both sides, have same date but different filesizes -Pliki, które istnieją po obu stronach, mają tą samą datę ale inny rozmiar Files that exist on both sides, left one is newer Pliki, które istnieją po obu stronach, lewa strona jest nowsza Files that exist on both sides, right one is newer @@ -412,8 +414,8 @@ FreeFileSync configuration Konfiguracja FreeFileSync FreeFileSync is up to date! FreeFileSync jest już uaktualniony! -Full name -Pełna nazwa +Full path +Pełna scieżka Generating file list... Generowanie listy plików... Global settings @@ -422,6 +424,8 @@ Help Pomoc Hide all error and warning messages Ukryj wszystkie informacje błędach i ostrzeżeniach +Hide conflicts +Ukryj konflikty Hide files that are different Ukryj pliki, które są różne Hide files that are equal @@ -434,6 +438,12 @@ Hide files that exist on left side only Ukryj pliki, które istnieją tylko po lewej stronie Hide files that exist on right side only Ukryj pliki, które istnieją tylko po prawej stronie +Hide files that will be copied to the left side +Ukryj pliki, które będą kopiowane na lewą stronę +Hide files that will be copied to the right side +Ukryj pliki, które będą kopiowane na prawą stronę +Hide files that won't be copied +Ukryj pliki, które nie będą kopiowane Hide filtered items Ukryj elementy przefiltrowane Hide further error messages during the current process @@ -446,6 +456,8 @@ Homepage Strona domowa If you like FFS Jeżeli Ci się podoba +Ignore 1-hour file time difference +Ignoruj 1-godzinną różnicę między plikami Ignore errors Ignoruj błędy Ignore subsequent errors @@ -458,8 +470,8 @@ Include Dołącz Include temporarily Dołącz tymczasowo -Include: *.doc;*.zip;*.exe\nExclude: *\\temp\\* -Dołącz: *.doc;*.zip;*.exe\nWyklucz: *\\temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\temp\\* +Dołącz: *.doc;*.zip;*.exe\nWyklucz: \\temp\\* Info Info Information @@ -470,8 +482,6 @@ It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are n Inicjalizacja Kosza nie była możliwa!\n\nPrawdopodobnie nie używasz Windowsa.\nJeżeli chcesz dołączyć tą cechę, skontaktuj się z autorem. :) Left: Lewy: -Legend -Legenda Load configuration from file Wczytaj konfigurację z pliku Load configuration history (press DEL to delete items) @@ -490,8 +500,8 @@ Move column down Przesuń kolumnę w dół Move column up Przesuń kolumnę do góry -Not all items were synchronized! Have a look at the list. -Nie wszystkie elementy zostały zsynchronizowane! Lista pominiętych plików. +Not all items have been synchronized! Have a look at the list. +Nie wszystkie elementy zostały zsynchronizowane! Zobacz tą listę. Not enough free disk space available in: Brak wystarczającej przestrzeni dyskowej na: Nothing to synchronize according to configuration! @@ -504,10 +514,8 @@ Number of files that will be overwritten Liczba plików, które zostaną nadpisane OK OK -Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the full name including path prefix. -Tylko pliki/katalogi, które nie zostaną odrzucone przez filtr zostaną zsynchronizowane. Filtr jest stosowany tylko dla pełnej nazwy pliku. -Open synchronization dialog -Przejdź do ustawień zaawansowanych synchronizacji +Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the name relative(!) to the synchronization directories. +Tylko pliki/katalogi, które nie zostaną odrzucone przez filtr zostaną dodane do procesu synchronizacji. Filtr działa tylko dla nazw wprowadzonych relatywnie(!) Open with File Manager\tD-Click Exploruj Operation aborted! @@ -528,6 +536,8 @@ Preview Podgląd Published under the GNU General Public License: Udostępnione na zasadach licencji GNU General Public License: +Question +Pytanie Quit Zakończ Relative path @@ -536,18 +546,20 @@ Remove folder pair Usuń parę folderów Reset Resetuj +Reset all warning messages +Resetuj wszystkie ostrzeżenia Reset all warning messages? Zresetować wszystkie ostrzeżenia? -Resets all warning messages -Zresetuj wszystkie ostrzeżenia Result Rezultat Right: Prawy: S&ave configuration Z&apisz konfigurację -Save aborted! -Speicherung abgebrochen! +S&witch view +P&rzełącz widok +Save changes to current configuration? +Zapisać zmiany obecnej konfiguracji? Save current configuration to file Zapisz aktualny plik konfiguracyjny Scanning... @@ -560,6 +572,10 @@ Select logfile directory: Wybierz katalog z logami: Select variant: Wybierz wariant: +Show conflicts +Pokaż konflikty +Show file icons +Ukryj ikony plików Show files that are different Pokaż pliki, które się różnią Show files that are equal @@ -572,6 +588,12 @@ Show files that exist on left side only Pokaż pliki istniejące tylko po lewej stronie Show files that exist on right side only Pokaż pliki istniejące tylko po prawej stronie +Show files that will be copied to the left side +Pokaż pliki, które będą kopiowane na lewą stronę +Show files that will be copied to the right side +Pokaż pliki, które będą kopiowane na prawą stronę +Show files that won't be copied +Pokaż pliki, które nie będą kopiowane Show popup Pokaż okno popup Show popup on errors or warnings @@ -596,6 +618,8 @@ Stop Zatrzymaj Swap sides Zamień stronami +Synchronization Preview +Podgląd synchronizacji Synchronization aborted! Synchronizacja przerwana! Synchronization completed successfully! @@ -608,8 +632,8 @@ Synchronization settings Ustawienia synchronizacji Synchronization status Status synchronizacji -Synchronize all .doc, .zip and .exe files except everything from folder \"temp\". -Synchronizuj wszystkie pliki .doc, .zip i .exe z wyjątkiem folderu \"temp\". +Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". +Synchronizuj wszystkie pliki .doc, .zip i exe z wyjątkiem folderu \"temp\" Synchronize both sides simultaneously: Copy new or updated files in both directions. Synchronizuj obie strony jednocześnie: Kopiuj nowe albo uaktualniaj w obu folderach. Synchronizing... @@ -636,6 +660,8 @@ Total required free disk space: Całkowita wymagana przestrzeń dyskowa: Total time: Całkowity czas: +Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes. +Traktuj pliki różniące się dokładnie +/- 1 godzinę jako równe, mniej niż 1 godzinę jako konflikt by uwzględnić zmiane czasu letniego. Two way <-> Obustronna <-> Unable to connect to sourceforge.net! @@ -646,10 +672,10 @@ Unable to initialize Recycle Bin! Nie można zainicjalizować Kosz! Uncheck all Odznacz wszystko +Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. +Istnieją nierozwiązane konflikty! \n\nMożesz je zignorować i kontynułować synchronizację. Update -> Uaktualnij -> -Update: -Uaktualnij: Use Recycle Bin Użyj kosza Use Recycle Bin when deleting or overwriting files during synchronization @@ -668,6 +694,8 @@ different różny file exists on both sides plik istnieje po obu stronach +flash conflict\n +konflikt\n on one side only tylko po jednej stronie |> file on right side only\n diff --git a/Languages/portuguese.lng b/Languages/portuguese.lng index 8fdef162..5808fe8d 100644 --- a/Languages/portuguese.lng +++ b/Languages/portuguese.lng @@ -44,8 +44,6 @@ &Cancelar &Check for new version &Procurar actualizações -&Compare -&Comparar &Create batch job &Criar um ficheiro batch &Default @@ -66,6 +64,8 @@ &Carregar &Load configuration &Carregar configuração +&No +&Não &OK &OK &Pause @@ -76,16 +76,18 @@ &Tentar de Novo &Save &Guardar -&Start -&Arrancar -&Synchronize... -&Sincronizar... +&Yes +&Sim , +- do not copy\n +- não copiar\n +- conflict +- conflito +- conflict (same date, different size) +- conflito (mesma data, tamanho diferente) - different - ficheiros diferentes -- different (same date, different size) -- ficheiros diferentes (mesma data, tamanho diferente) - equal - ficheiros iguais - exists left only @@ -100,8 +102,8 @@ - direita - right newer - mais novo à direita -- same date (different size) -- mesma data (tamanho diferente) +-> copy to right side\n +-> copiar para a direita\n -Open-Source file synchronization- -Sincronização de ficheiros Open-Source- . @@ -114,16 +116,16 @@ 1 ficheiro, 1. &Compare 1. &Comparar -1. Enter full file or directory names separated by ';' or a new line. -1. Introduzir nome completo dos ficheiros ou pastas separados por ';' ou uma nova linha. +1. Enter relative file or directory names separated by ';' or a new line. +1. Inserir caminho(s) do(s) ficheiro(s) ou pasta(s) separados por ';' ou numa nova linha. 2. &Synchronize... 2. &Sincronizar... 2. Use wildcard characters '*' and '?'. 2. Usar '*' e '?' como caracteres de procura. 3. Exclude files directly on main grid via context menu. 3. Excluir ficheiros directamente da grelha através do menu de contexto. -4. Keep the number of (different) entries small for best performance. -4. Manter o número de entradas (diferentes) pequeno para melhor performance. +<- copy to left side\n +<- copiar para a esquerda\n << left file is newer\n << ficheiro à esquerda mais recente\n <Directory> @@ -134,8 +136,8 @@ <Selecção Múltipla> <| file on left side only\n <| ficheiro apenas à esquerda\n -== files are equal\n\n -== ficheiros iguais\n\n +== files are equal\n +== ficheiros iguais\n >> right file is newer\n >> ficheiro à direita mais recente\n A newer version of FreeFileSync is available: @@ -168,6 +170,8 @@ Batch job Ficheiro Batch Big thanks for localizing FreeFileSync goes out to: Pela tradução de FreeFileSync, um agradecimento a: +Browse +Procurar Build: Criado: Cancel @@ -178,6 +182,8 @@ Choose to hide filtered files/directories from list Ocultar itens filtrados da lista Comma separated list Lista de itens separados por virgula +Compare +Comparar Compare both sides Comparar listas Compare by \"File content\" @@ -190,8 +196,10 @@ Comparing content A comparar conteúdo Comparing content of files %x A comparar o conteúdo do ficheiro %x -Comparing... +Comparing content... A comparar... +Comparison Result +Resultado comparação Completed Terminado Configuration @@ -234,8 +242,6 @@ Could not set working directory: Não pode definir pasta de trabalho: Create a batch job Criar ficheiro batch -Create: -Criar: Creating folder %x Criar pasta %x Current operation: @@ -248,8 +254,6 @@ DECISION TREE ÁRVORE DE DECISÃO Data remaining: Dados em falta: -Data: -Dados: Date Data Delete files/folders existing on left side only @@ -262,8 +266,6 @@ Delete on both sides Eliminar em ambos os lados Delete on both sides even if the file is selected on one side only Eliminar em ambos os lados mesmo se o ficheiro só está seleccionado num lado -Delete: -Eliminar: Deleting file %x Apagar ficheiro %x Deleting folder %x @@ -286,6 +288,8 @@ Do you really want to move the following objects(s) to the Recycle Bin? Quer mesmo mover o(s) seguinte(s) objecto(s) para a Reciclagem? Do you want FreeFileSync to automatically check for updates every week? Deseja que o FreeFileSync procure automaticamente actualizações todas as semanas? +Don't ask me again +Não perguntar de novo Donate with PayPal Doar usando PayPal Download now? @@ -374,8 +378,6 @@ Files remaining: Ficheiros restantes: Files that exist on both sides and have different content Ficheiros existentes dos dois lados e com conteúdo diferente -Files that exist on both sides, have same date but different filesizes -Ficheiros existentes dos dois lados com a mesma data, mas tamnhos diferentes Files that exist on both sides, left one is newer Ficheiros existentes dos dois lados, à esquerda é mais recente Files that exist on both sides, right one is newer @@ -412,8 +414,8 @@ FreeFileSync configuration FreeFileSync configuração FreeFileSync is up to date! FreeFileSync está actualizado! -Full name -Nome completo +Full path +Caminho completo Generating file list... A gerar lista ficheiros... Global settings @@ -422,6 +424,8 @@ Help Ajuda Hide all error and warning messages Ocultar todas as mensagens de erro ou aviso +Hide conflicts +Ocultar conflitos Hide files that are different Ocultar ficheiros diferentes Hide files that are equal @@ -434,6 +438,12 @@ Hide files that exist on left side only Ocultar ficheiros existentes somente à esquerda Hide files that exist on right side only Ocultar ficheiros existentes somente à direita +Hide files that will be copied to the left side +Ocultar ficheiros a copiar para a esquerda +Hide files that will be copied to the right side +Ocultar ficheiros a copiar para a direita +Hide files that won't be copied +Ocultar ficheiros que não serão copiados Hide filtered items Ocultar itens filtrados Hide further error messages during the current process @@ -446,6 +456,8 @@ Homepage Site If you like FFS Se gosta do FreeFileSync +Ignore 1-hour file time difference +Ignorar diferenças de 1 hora entre ficheiros Ignore errors Ignorar erros Ignore subsequent errors @@ -458,8 +470,8 @@ Include Incluir Include temporarily Incluir temporariamente -Include: *.doc;*.zip;*.exe\nExclude: *\\temp\\* -Incluir: *.doc;*.zip;*.exe\nExcluir: *\\temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\temp\\* +Incluir: *.doc;*.zip;*.exe\nExcluir: \\temp\\* Info Info Information @@ -470,8 +482,6 @@ It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are n Não é possível aceder à Reciclagem!\n\nÉ possível que não esteja a utilizar Windows.\nSe desejar esta opção incluída, é favor contactar o autor. :) Left: Esquerda: -Legend -Legenda Load configuration from file Carregar configuração do ficheiro Load configuration history (press DEL to delete items) @@ -490,8 +500,8 @@ Move column down Mover coluna para baixo Move column up Mover coluna para cima -Not all items were synchronized! Have a look at the list. -Nem todos os itens foram sincronizados! Por favor, verifique a lista. +Not all items have been synchronized! Have a look at the list. +Nem todos os ficheiros foram sincronizados! Verifique a lista. Not enough free disk space available in: Não há espaço livre suficiente em: Nothing to synchronize according to configuration! @@ -504,10 +514,8 @@ Number of files that will be overwritten Número de ficheiros substituidos OK OK -Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the full name including path prefix. -Apenas ficheiros/pastas que passem a filtragem serão seleccionados para sincronização. O filtro será aplicado ao nome completo, incluindo o caminho. -Open synchronization dialog -Abrir diálogo de sincronização +Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the name relative(!) to the synchronization directories. +Apenas ficheiros/pastas que passem o filtro serão selecionados para sincronização. O filtro será aplicado no nome relativo às pastas em sincronização. Open with File Manager\tD-Click Abrir c/ Gestor de Ficheiros\tD-Click Operation aborted! @@ -528,6 +536,8 @@ Preview Pré-visualizar Published under the GNU General Public License: Publicado sobre GNU General Public License: +Question +Questão Quit Sair Relative path @@ -536,18 +546,20 @@ Remove folder pair Remover o par de pastas Reset Reiniciar +Reset all warning messages +Reiniciar todas mensagens de aviso Reset all warning messages? -Reiniciar mensagens de aviso? -Resets all warning messages -Reinicia mensagens de aviso +Reiniciar todas mensagens de aviso? Result Resultado Right: Direita: S&ave configuration G&uardar a configuração -Save aborted! -Guardar abortado! +S&witch view +&Mudar vista +Save changes to current configuration? +Guardar alterações à configuração? Save current configuration to file Guardar o corrente ficheiro de configuração Scanning... @@ -560,6 +572,10 @@ Select logfile directory: Seleccione directório para ficheiro log: Select variant: Seleccione uma variante: +Show conflicts +Mostrar conflitos +Show file icons +Mostrar icones dos ficheiros Show files that are different Mostrar ficheiros diferentes Show files that are equal @@ -572,6 +588,12 @@ Show files that exist on left side only Mostrar ficheiros existentes somente à esquerda Show files that exist on right side only Mostrar ficheiros existentes somente à direita +Show files that will be copied to the left side +Mostrar ficheiros a copiar para a esquerda +Show files that will be copied to the right side +Mostrar ficheiros a copiar para a direita +Show files that won't be copied +Mostrar ficheiros que não serão copiados Show popup Mostrar popups Show popup on errors or warnings @@ -596,6 +618,8 @@ Stop Parar Swap sides Trocar lados +Synchronization Preview +Previsualizar sincronização Synchronization aborted! Sincronização abortada! Synchronization completed successfully! @@ -608,8 +632,8 @@ Synchronization settings Parâmetros de sincronização Synchronization status Estado da sincronização -Synchronize all .doc, .zip and .exe files except everything from folder \"temp\". -Sincronizar todos os ficheiros .doc, .zip and .exe excepto os da pasta \"temp\". +Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". +Sincronizar todos os ficheiros .doc, .zip e .exe excepto os da pasta \"temp\". Synchronize both sides simultaneously: Copy new or updated files in both directions. Sincronizar ambos os lados simultaneamente: Copiar os ficheiros novos ou mais recentes em ambas as direcções. Synchronizing... @@ -636,6 +660,8 @@ Total required free disk space: Espaço livre necessário: Total time: Tempo total: +Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes. +Tratar ficheiros com exactamente +/- 1 hora como iguais, e menos de 1 hora como conflito, para salvaguardar a alteração da Hora de Verão. Two way <-> 2 sentidos <-> Unable to connect to sourceforge.net! @@ -646,10 +672,10 @@ Unable to initialize Recycle Bin! Não é possível iniciar a Reciclagem! Uncheck all Deseleccionar todos +Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. +Existem conflitos não resolvidos! \n\nPode ignorá-los e continuar a sincronização. Update -> Actualizar -> -Update: -Actualizar: Use Recycle Bin Utilizar Reciclagem Use Recycle Bin when deleting or overwriting files during synchronization @@ -668,6 +694,8 @@ different ficheiros diferentes file exists on both sides ficheiro existente em ambos os lados +flash conflict\n +relâmpago conflito\n on one side only ficheiro existente apenas num lado |> file on right side only\n diff --git a/Languages/portuguese_br.lng b/Languages/portuguese_br.lng index 0e7f43f6..a8af22da 100644 --- a/Languages/portuguese_br.lng +++ b/Languages/portuguese_br.lng @@ -44,8 +44,6 @@ &Cancelar &Check for new version &Procurar novas versões -&Compare -&Comparar &Create batch job &Criar um arquivo batch &Default @@ -66,6 +64,8 @@ &Carregar &Load configuration &Carregar configuração +&No + &OK &OK &Pause @@ -76,16 +76,18 @@ &Tentar de Novo &Save &Salvar -&Start -&Iniciar -&Synchronize... -&Sincronizar... +&Yes + , . +- do not copy\n + +- conflict + +- conflict (same date, different size) + - different - diferente -- different (same date, different size) -- diferente (mesma data, tamanho diferente) - equal - igual - exists left only @@ -100,8 +102,8 @@ - direita - right newer - mais recente à direita -- same date (different size) -- mesma data (tamanho diferente) +-> copy to right side\n + -Open-Source file synchronization- -Sincronização de Arquivos Open-Source- . @@ -114,16 +116,16 @@ 1 arquivo, 1. &Compare 1. &Comparar -1. Enter full file or directory names separated by ';' or a new line. -1. Introduzir nome completo dos arquivos ou pastas separados por ';' ou uma nova linha. +1. Enter relative file or directory names separated by ';' or a new line. + 2. &Synchronize... 2. &Sincronizar... 2. Use wildcard characters '*' and '?'. 2. Usar '*' e '?' como caracteres de procura. 3. Exclude files directly on main grid via context menu. 3. Excluir arquivos diretamente do grid principal através do menu de contexto. -4. Keep the number of (different) entries small for best performance. -4. Manter o número de entradas (diferentes) pequeno para melhor desempenho. +<- copy to left side\n + << left file is newer\n << arquivo à esquerda é mais recente\n <Directory> @@ -134,8 +136,8 @@ <seleção múltipla> <| file on left side only\n <| arquivo apenas à esquerda\n -== files are equal\n\n -== arquivos são iguais\n\n +== files are equal\n + >> right file is newer\n >> arquivo à direita é mais recente\n A newer version of FreeFileSync is available: @@ -168,6 +170,8 @@ Batch job Arquivo Batch Big thanks for localizing FreeFileSync goes out to: Pela tradução do FreeFileSync, um agradecimento a: +Browse + Build: Criado: Cancel @@ -178,6 +182,8 @@ Choose to hide filtered files/directories from list Ocultar arquivos/diretórios filtrados da lista Comma separated list Lista de itens separada por vírgula +Compare + Compare both sides Comparar os dois lados Compare by \"File content\" @@ -190,8 +196,10 @@ Comparing content Comparando conteúdo Comparing content of files %x Comparando conteúdo do arquivo %x -Comparing... -Comparando... +Comparing content... + +Comparison Result + Completed Finalizado Configuration @@ -234,8 +242,6 @@ Could not set working directory: Não se pode definir pasta de trabalho: Create a batch job Criar arquivo batch -Create: -Criar: Creating folder %x Criando pasta %x Current operation: @@ -248,8 +254,6 @@ DECISION TREE ÁRVORE DE DECISÃO Data remaining: Dados faltantes: -Data: -Dados: Date Data Delete files/folders existing on left side only @@ -262,8 +266,6 @@ Delete on both sides Apagar em ambos os lados Delete on both sides even if the file is selected on one side only Apagar em ambos os lados mesmo se o arquivo está selecionado só em um lado -Delete: -Apagar: Deleting file %x Apagando arquivo %x Deleting folder %x @@ -286,6 +288,8 @@ Do you really want to move the following objects(s) to the Recycle Bin? Quer mesmo mover o(s) seguinte(s) item(s) para a Lixeira? Do you want FreeFileSync to automatically check for updates every week? Deseja que o FreeFileSync procure automaticamente novas versões toda semana? +Don't ask me again + Donate with PayPal Doar usando PayPal Download now? @@ -374,8 +378,6 @@ Files remaining: Arquivos restantes: Files that exist on both sides and have different content Arquivos que existem nos dois lados e têm conteúdo diferente -Files that exist on both sides, have same date but different filesizes -Arquivos que existem nos dois lados, têm a mesma data mas tamanhos diferentes Files that exist on both sides, left one is newer Arquivos que existem nos dois lados, sendo à esquerda mais recentes Files that exist on both sides, right one is newer @@ -412,8 +414,8 @@ FreeFileSync configuration FreeFileSync configuração FreeFileSync is up to date! FreeFileSync está atualizado! -Full name -Nome completo +Full path + Generating file list... Gerando lista de arquivos... Global settings @@ -422,6 +424,8 @@ Help Ajuda Hide all error and warning messages Ocultar todas as mensagens de erro ou aviso +Hide conflicts + Hide files that are different Ocultar arquivos que são diferentes Hide files that are equal @@ -434,6 +438,12 @@ Hide files that exist on left side only Ocultar arquivos que existem somente à esquerda Hide files that exist on right side only Ocultar arquivos que existem somente à direita +Hide files that will be copied to the left side + +Hide files that will be copied to the right side + +Hide files that won't be copied + Hide filtered items Ocultar itens filtrados Hide further error messages during the current process @@ -446,6 +456,8 @@ Homepage Homepage If you like FFS Se gosta do FFS +Ignore 1-hour file time difference + Ignore errors Ignorar erros Ignore subsequent errors @@ -458,8 +470,8 @@ Include Incluir Include temporarily Incluir temporariamente -Include: *.doc;*.zip;*.exe\nExclude: *\\temp\\* -Incluir: *.doc;*.zip;*.exe\nExcluir: *\\temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\temp\\* + Info Info Information @@ -470,8 +482,6 @@ It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are n Não foi possível acessar a Lixeira!\n\nÉ possível que não esteja utilizando Windows.\nSe desejar esta opção incluída, favor contatar o autor. :) Left: Esquerda: -Legend -Legenda Load configuration from file Carregar configuração do arquivo Load configuration history (press DEL to delete items) @@ -490,8 +500,8 @@ Move column down Mover coluna para baixo Move column up Mover coluna para cima -Not all items were synchronized! Have a look at the list. -Nem todos os itens foram sincronizados! Verifique a lista. +Not all items have been synchronized! Have a look at the list. + Not enough free disk space available in: Espaço em disco insuficiente em: Nothing to synchronize according to configuration! @@ -504,10 +514,8 @@ Number of files that will be overwritten Número de arquivos que serão substituídos OK OK -Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the full name including path prefix. -Apenas arquivos/diretórios que passem a filtragem serão selecionados para sincronização. O filtro será aplicado ao nome completo, incluindo o prefixo do caminho. -Open synchronization dialog -Abrir opções de sincronização +Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the name relative(!) to the synchronization directories. + Open with File Manager\tD-Click Abrir com Gerenciador de Arquivos\tD-Click Operation aborted! @@ -528,6 +536,8 @@ Preview Pré-visualização Published under the GNU General Public License: Publicado sobre a GNU General Public License: +Question + Quit Sair Relative path @@ -536,18 +546,20 @@ Remove folder pair Remover par de pastas Reset Reiniciar +Reset all warning messages + Reset all warning messages? Reiniciar todas as mensagens de aviso? -Resets all warning messages -Reinicia todas as mensagens de aviso Result Resultado Right: Direita: S&ave configuration S&alvar configuração -Save aborted! -Salvar cancelado! +S&witch view + +Save changes to current configuration? + Save current configuration to file Salvar configuração atual para arquivo Scanning... @@ -560,6 +572,10 @@ Select logfile directory: Escolha um diretório para salvar o arquivo log: Select variant: Selecione uma variante: +Show conflicts + +Show file icons + Show files that are different Mostrar arquivos que são diferentes Show files that are equal @@ -572,6 +588,12 @@ Show files that exist on left side only Mostrar arquivos que existem somente à esquerda Show files that exist on right side only Mostrar arquivos que existem somente à direita +Show files that will be copied to the left side + +Show files that will be copied to the right side + +Show files that won't be copied + Show popup Mostrar popup Show popup on errors or warnings @@ -596,6 +618,8 @@ Stop Parar Swap sides Inverter lados +Synchronization Preview + Synchronization aborted! Sincronização cancelada! Synchronization completed successfully! @@ -608,8 +632,8 @@ Synchronization settings Parâmetros de sincronização Synchronization status Estado da sincronização -Synchronize all .doc, .zip and .exe files except everything from folder \"temp\". -Sincronizar todos os arquivos .doc, .zip and .exe exceto os da pasta \"temp\". +Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". + Synchronize both sides simultaneously: Copy new or updated files in both directions. Sincronizar ambos os lados simultaneamente: Copiar os arquivos novos ou mais recentes em ambas as direções. Synchronizing... @@ -636,6 +660,8 @@ Total required free disk space: Espaço livre total requerido: Total time: Tempo total: +Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes. + Two way <-> Dois sentidos <-> Unable to connect to sourceforge.net! @@ -646,10 +672,10 @@ Unable to initialize Recycle Bin! Não foi possível inicializar a Lixeira! Uncheck all Deselecionar todos +Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. + Update -> Atualizar -> -Update: -Atualizar: Use Recycle Bin Utilizar Lixeira Use Recycle Bin when deleting or overwriting files during synchronization @@ -668,6 +694,8 @@ different diferente file exists on both sides arquivo existe em ambos os lados +flash conflict\n + on one side only existente apenas em um lado |> file on right side only\n diff --git a/Languages/slovenian.lng b/Languages/slovenian.lng index 1eec886b..ee021d62 100644 --- a/Languages/slovenian.lng +++ b/Languages/slovenian.lng @@ -44,8 +44,6 @@ &Prekliči &Check for new version &Preveri za novo različico -&Compare -&Primerjaj &Create batch job &Ustvari batch opravilo &Default @@ -66,26 +64,30 @@ &Naloži &Load configuration Na&loži konfiguracijo +&No +&Ne &OK &V redu &Pause &Pavza &Quit -&Zapusti +&Zapri &Retry &Ponovi &Save &Shrani -&Start -&Začni -&Synchronize... -&Sinhroniziraj... +&Yes +&Da , , +- do not copy\n +- ne kopiraj\n +- conflict +- spor +- conflict (same date, different size) +- spor (isti datum, različna velikost) - different - različni -- different (same date, different size) -- različni (enak datum, različna velikost) - equal - enaki - exists left only @@ -100,8 +102,8 @@ Na&loži konfiguracijo - desno - right newer - desna novejša -- same date (different size) -- enak datum (različna velikost) +-> copy to right side\n +-> kopiraj na desno stran\n -Open-Source file synchronization- -Odprto-kodna sinhronizacija datotek- . @@ -114,16 +116,16 @@ Na&loži konfiguracijo 1 datoteka, 1. &Compare 1. &Primerjaj -1. Enter full file or directory names separated by ';' or a new line. -1. Vnesite polno ime datotek ali imenikov ločenih s ';' ali novo vrstico. +1. Enter relative file or directory names separated by ';' or a new line. +1. Vnesite relativna imena datotek ali imenikov ločenih z ';' ali novo vrstico. 2. &Synchronize... 2. &Sinhroniziraj... 2. Use wildcard characters '*' and '?'. 2. Uporabite lahko tudi znake '*' in '?'. 3. Exclude files directly on main grid via context menu. 3. Izključite datoteke neposredno na glavni mreži s kontekstnim menujem. -4. Keep the number of (different) entries small for best performance. -4. Za boljšo učinkovitost ohranjajte število (različnih) vnosov majhno. +<- copy to left side\n +<- kopiraj na levo stran\n << left file is newer\n << leva datoteka je novejša\n <Directory> @@ -134,8 +136,8 @@ Na&loži konfiguracijo <mnogokratna izbira> <| file on left side only\n <| datoteka obstaja samo na levi\n -== files are equal\n\n -== datoteki sta enaki\n\n +== files are equal\n +== datoteki sta enaki\n >> right file is newer\n >> desna datoteka je novejša\n A newer version of FreeFileSync is available: @@ -168,6 +170,8 @@ Batch job Batch opravilo Big thanks for localizing FreeFileSync goes out to: Zahvale za prevod FreeFileSync gredo: +Browse +Brskaj Build: Izgradnja: Cancel @@ -178,6 +182,8 @@ Choose to hide filtered files/directories from list Skrij filtrirane datoteke/imenike iz seznama Comma separated list Seznam ločen z vejico +Compare +Primerjaj Compare both sides Primerjaj obe strani Compare by \"File content\" @@ -190,8 +196,10 @@ Comparing content Primerjam vsebino Comparing content of files %x Primerjam vsebino datotek %x -Comparing... -Primerjam... +Comparing content... +Primerjam vsebino... +Comparison Result +Rezultati primerjave Completed Zaključeno Configuration @@ -234,8 +242,6 @@ Could not set working directory: Ne morem nastaviti delovnega imenika: Create a batch job Ustvari batch opravilo -Create: -Ustvari: Creating folder %x Ustvarjam mapo %x Current operation: @@ -248,8 +254,6 @@ DECISION TREE DREVO ODLOČITEV Data remaining: Preostanek podatkov: -Data: -Podatki: Date Datum Delete files/folders existing on left side only @@ -262,8 +266,6 @@ Delete on both sides Izbriši na obeh straneh Delete on both sides even if the file is selected on one side only Izbriši na obeh straneh, četudi je datoteka izbrana na samo eni strani -Delete: -Izbriši: Deleting file %x Brisanje datoteke %x Deleting folder %x @@ -286,6 +288,8 @@ Do you really want to move the following objects(s) to the Recycle Bin? Ali resnično želite premakniti naslednje objekte v Koš? Do you want FreeFileSync to automatically check for updates every week? Ali želite, da FreeFileSync samodejno preverja za posodobitve vsak teden? +Don't ask me again +Ne sprašuj me več Donate with PayPal Doniraj s PayPal Download now? @@ -367,15 +371,13 @@ File times that differ by up to the specified number of seconds are still handle Filename Ime datoteke Files are found equal if\n - file content\nis the same. -Datoteke so enake če\n - je vsebina datoteke\nenaka. +Datoteki sta enaki, če\n - je vsebina datoteke\nenaka. Files are found equal if\n - filesize\n - last write time and date\nare the same. -Datoteke so enake če\n - velikost datoteke\n - zadnji čas pisanja in datum\nso enaki. +Datoteki sta enaki, če so\n - velikost datoteke\n - zadnji čas spremembe in datum\nenaki. Files remaining: Preostale datoteke: Files that exist on both sides and have different content Datoteke, ki obstajajo na obeh straneh in imajo različno vesbino -Files that exist on both sides, have same date but different filesizes -Datoteke, ki obstajajo na obeh straneh, imajo isti datum, vendar so različnih velikosti Files that exist on both sides, left one is newer Datoteke, ki obstajajo na obeh straneh, leva je novejša Files that exist on both sides, right one is newer @@ -412,8 +414,8 @@ FreeFileSync configuration FreeFileSync konfiguracija FreeFileSync is up to date! FreeFileSync je posodobljen! -Full name -Polno ime +Full path +Polna pot Generating file list... Ustvarjam seznam datotek... Global settings @@ -422,6 +424,8 @@ Help Pomoč Hide all error and warning messages Skrij vsa obvestila o napakah in opozorilih +Hide conflicts +Skrij spore Hide files that are different Skrij datoteke ki so različne Hide files that are equal @@ -434,6 +438,12 @@ Hide files that exist on left side only Skrij datoteke, ki obstajajo samo na levi strani Hide files that exist on right side only Skrij datoteke, ki obstajajo samo na desni strani +Hide files that will be copied to the left side +Skrij datoteke, ki bodo kopirane na levo stran +Hide files that will be copied to the right side +Skrij datoteke, ki bodo kopirane na desno stran +Hide files that won't be copied +Skrij datoteke, ki ne bodo kopirane Hide filtered items Skrij filtrirane predmete Hide further error messages during the current process @@ -446,6 +456,8 @@ Homepage Domača stran If you like FFS Če vam je FFS všeč +Ignore 1-hour file time difference +Ignoriraj 1-urno časovno razliko Ignore errors Ignoriraj napake Ignore subsequent errors @@ -458,8 +470,8 @@ Include Vključi Include temporarily Trenutno vključi -Include: *.doc;*.zip;*.exe\nExclude: *\\temp\\* -Vključi: *.doc;*.zip;*.exe\nIzključi: *\\temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\temp\\* +Vključi: *.doc;*.zip;*.exe\nIzključi: \\temp\\* Info Info Information @@ -470,8 +482,6 @@ It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are n Ni bilo mogoče inicializirati Koša!\n\nZgleda, da ne uporabljate Windowsov.\nČe želite imeti vključeno to lastnost, prosimo kontaktirajte avtorja. :) Left: Levo: -Legend -Legenda Load configuration from file Naloži konfiguracijo iz datoteke Load configuration history (press DEL to delete items) @@ -490,8 +500,8 @@ Move column down Premakni stolpec dol Move column up Premakni stolpec gor -Not all items were synchronized! Have a look at the list. -Vsi predmeti niso bili sinhronizirani! Poglejte seznam. +Not all items have been synchronized! Have a look at the list. +Vse stvari niso bile sinhronizirane! Preglejte seznam. Not enough free disk space available in: Na voljo ni dovolj prostega prostora na disku v: Nothing to synchronize according to configuration! @@ -504,10 +514,8 @@ Number of files that will be overwritten Število datotek, ki bodo prepisane OK V redu -Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the full name including path prefix. -Samo datoteke/imeniki, ki preidejo filtriranje bodo izbrane za sinhronizacijo. Filter bo uveljavljen na polno ime vključujoč predpono. -Open synchronization dialog -Odpri sinhronizacijsko pogovorno okno +Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the name relative(!) to the synchronization directories. +Samo datoteke/imeniki, ki preidejo skozi filtriranje bodo izbrane za sinhronizacijo. Filter bo uveljavljen na ime relativno(!) glede na sinhronizacijske imenike. Open with File Manager\tD-Click Odpri z urejevalnikom datotek\tD-Click Operation aborted! @@ -528,6 +536,8 @@ Preview Predogled Published under the GNU General Public License: Objavljeno pod licenco GNU General Public: +Question +Vprašanje Quit Zapusti Relative path @@ -536,18 +546,20 @@ Remove folder pair Odstrani par imenikov Reset Ponastavi +Reset all warning messages +Ponastavi vsa obvestila z opozorili Reset all warning messages? Ponastavim vsa obvestila z opozorili? -Resets all warning messages -Ponastavi vsa obvestila z opozorili Result Rezultat Right: Desno: S&ave configuration Shr&ani konfiguracijo -Save aborted! -Shranjevanje prekinjeno! +S&witch view +Sp&remeni pogled +Save changes to current configuration? +Shranim spremembe trenutne konfiguracije? Save current configuration to file Shrani trenutno konfiguracijo v datoteko Scanning... @@ -560,6 +572,10 @@ Select logfile directory: Izberite imenik datoteke za beleženje: Select variant: Izberite varianto: +Show conflicts +Prikaži spore +Show file icons +Prikaži ikone datotek Show files that are different Prikaži datoteke, ki so različne Show files that are equal @@ -572,6 +588,12 @@ Show files that exist on left side only Prikaži datoteke, ki obstajajo samo na levi Show files that exist on right side only Prikaži datoteke, ki obstajajo samo na desni +Show files that will be copied to the left side +Prikaži datoteke, ki bodo kopirane na levo stran +Show files that will be copied to the right side +Prikaži datoteke, ki bodo kopirane na desno stran +Show files that won't be copied +Prikaži datoteke, ki ne bodo kopirane Show popup Prikaži pojavno okno Show popup on errors or warnings @@ -596,6 +618,8 @@ Stop Ustavi Swap sides Zamenjaj strani +Synchronization Preview +Predogled sinhronizacije Synchronization aborted! Sinhronizacija prekinjena! Synchronization completed successfully! @@ -605,11 +629,11 @@ Sinhronizacija se je končala z napakami! Synchronization filter Filter sinhronizacije Synchronization settings -nastavitve sinhronizacije +Nastavitve sinhronizacije Synchronization status Status sinhronizacije -Synchronize all .doc, .zip and .exe files except everything from folder \"temp\". -Sinhroniziraj vse .doc, .zip in .exe datoteke, razen kar je v mapi \"temp\". +Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". +Sinhroniziraj vse .doc, .zip in .exe datoteke, razen iz podmape \"temp\". Synchronize both sides simultaneously: Copy new or updated files in both directions. Sinhroniziraj obe strani istočasno: Kopiraj nove ali posodobljene datoteke v obe smeri. Synchronizing... @@ -636,6 +660,8 @@ Total required free disk space: Skupno zahtevani prosti prostor na disku: Total time: Celoten čas: +Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes. +Obravnavaj čas spremembe datoteke, ki se razlikuje za točno +/- 1 uro kot enak, če pa je manjši kot 1 ura, pa kot spor, da lahko obravnavamo spremembe Poletnega časa. Two way <-> Obojesmerno <-> Unable to connect to sourceforge.net! @@ -646,14 +672,14 @@ Unable to initialize Recycle Bin! Ne morem inicializirati Koša! Uncheck all Odznači vse +Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. +Obstajajo nerešeni spori! \n\nLahko ignorirate spore in nadaljujete s sinhronizacijo. Update -> Posodobi -> -Update: -Posodobi: Use Recycle Bin Uporabi Koš Use Recycle Bin when deleting or overwriting files during synchronization -Uporabi Koš ko se briše ali prepisuje datoteke med sinhronizacijo +Uporabi Koš, ko se briše ali prepisuje datoteke med sinhronizacijo Warning Pozor Warning: Synchronization failed for %x item(s): @@ -668,6 +694,8 @@ different različni file exists on both sides datoteka obstaja na obeh straneh +flash conflict\n +strela spor\n on one side only samo na eni strani |> file on right side only\n diff --git a/Languages/spanish.lng b/Languages/spanish.lng index 8b771aa7..b27055a3 100644 --- a/Languages/spanish.lng +++ b/Languages/spanish.lng @@ -10,14 +10,24 @@ PB TB TB + day(s) + + hour(s) + kB kB + min + + sec + != files are different\n != los ficheros son diferentes\n %x directories %x directorios %x files, %x ficheros, +%x is not a valid FreeFileSync batch file! + %x of %y rows in view %x de %y ficheros %x of 1 row in view @@ -34,8 +44,6 @@ &Cancelar &Check for new version &Buscar versión nueva -&Compare -&Comparar &Create batch job &Crear un fichero batch &Default @@ -56,6 +64,8 @@ &Cargar &Load configuration &Cargar configuración +&No + &OK &OK &Pause @@ -66,16 +76,18 @@ &Reintentar &Save &Guardar -&Start -&Inicio -&Synchronize... -&Sincronizar... +&Yes + , , +- do not copy\n + +- conflict + +- conflict (same date, different size) + - different - ficheros diferentes -- different (same date, different size) -- ficheros diferentes (misma fecha, tamaño diferente) - equal - ficheros iguales - exists left only @@ -90,26 +102,30 @@ - derecha - right newer - el más nuevo en la derecha -- same date (different size) -- misma fecha (tamaño diferente) +-> copy to right side\n + -Open-Source file synchronization- -Sincronización de ficheros Open-Source- . , +/sec + 1 directory 1 directorio 1 file, 1 fichero, 1. &Compare 1. &Comparar -1. Enter full file or directory names separated by ';' or a new line. -1. Introducir nombre completo de fichero o directorio separado por ';' o una línea nueva. +1. Enter relative file or directory names separated by ';' or a new line. + 2. &Synchronize... 2. &Sincronizar... 2. Use wildcard characters '*' and '?'. 2. Usar '*' y '?' como caracteres comodín. 3. Exclude files directly on main grid via context menu. 3. Excluir directamente ficheros sobre la rejilla a través del menu de contexto. +<- copy to left side\n + << left file is newer\n << el fichero de la izquierda es el más nuevo\n <Directory> @@ -120,10 +136,12 @@ <Selección múltiple> <| file on left side only\n <| sólamente el fichero del lado izquierdo\n -== files are equal\n\n -== los ficheros son iguales\n\n +== files are equal\n + >> right file is newer\n >> el fichero de la derecha es el más nuevo\n +A newer version of FreeFileSync is available: + Abort requested: Waiting for current operation to finish... Abortar pedido: Esperar a que la actual operación finalice... Aborted @@ -152,6 +170,8 @@ Batch job Tarea Batch Big thanks for localizing FreeFileSync goes out to: Agradecimientos por la traducción de FreeFileSync a: +Browse + Build: Construído: Cancel @@ -162,6 +182,8 @@ Choose to hide filtered files/directories from list Ocultar en la lista ficheros/directorios filtrados Comma separated list Lista de "items" separados por coma +Compare + Compare both sides Comparar ambos lados Compare by \"File content\" @@ -174,8 +196,10 @@ Comparing content Comparación de contenido Comparing content of files %x Comparación del contenido de %x ficheros -Comparing... -Comparando... +Comparing content... + +Comparison Result + Completed Terminado Configuration @@ -212,12 +236,12 @@ Copy to clipboard\tCTRL+C Copiar al Portapapeles\tCTRL+C Copying file %x to %y Copiar fichero %x a %y +Copying file %x to %y overwriting target + Could not set working directory: No se pudo definir el directorio de trabajo: Create a batch job Crear una tarea "batch" -Create: -Crear: Creating folder %x Creando la carpeta %x Current operation: @@ -230,8 +254,6 @@ DECISION TREE ÁRBOL DE DECISIÓN Data remaining: Datos que faltan: -Data: -Datos: Date Fecha Delete files/folders existing on left side only @@ -244,16 +266,18 @@ Delete on both sides Eliminar en ambos lados lados Delete on both sides even if the file is selected on one side only Eliminar en ambos lados incluso si el fichero es seleccionado en un solo lado -Delete: -Eliminar: Deleting file %x Borrar fichero %x Deleting folder %x Borrar carpeta %x Directories are dependent! Be careful when setting up synchronization rules: ¡Los directorios son dependientes! Cuidado al establecer las reglas de sincronización: +Directory + Directory does not exist: El directorio no existe: +Do not display visual status information but write to a logfile instead + Do not show this warning again No mostrar este aviso otra vez Do nothing @@ -262,6 +286,10 @@ Do you really want to delete the following objects(s)? ¿Está seguro de querer borrar el/los siguiente(s) objeto(s)? Do you really want to move the following objects(s) to the Recycle Bin? ¿Está seguro de querer mover el/los siguiente(s) objeto(s) a la Papelera? +Do you want FreeFileSync to automatically check for updates every week? + +Don't ask me again + Donate with PayPal Donar usando PayPal Download now? @@ -270,6 +298,8 @@ Drag && drop Arrastrar Email Email +Enable filter to exclude files from synchronization + Error Error Error changing modification time: @@ -298,6 +328,8 @@ Error reading file: Error al leer el fichero: Error resolving symbolic link: Error al resolver enlace simbólico: +Error retrieving full path: + Error traversing directory: Error al trasladar directorio: Error writing file attributes: @@ -322,6 +354,8 @@ Feedback and suggestions are welcome at: Los comentarios y sugerencias será bienvenidos en: File Manager integration: Integración con el Explorador: +File Time tolerance (seconds): + File already exists. Overwrite? El fichero ya existe. ¿Sustituir? File content @@ -344,8 +378,6 @@ Files remaining: Ficheros restantes: Files that exist on both sides and have different content Ficheros que existen en ambos lados y tienen contenidos diferentes -Files that exist on both sides, have same date but different filesizes -Ficheros que existen en ambos lados, tienen la misma fecha pero diferentes tamaños Files that exist on both sides, left one is newer Ficheros que existen en ambos lados, el de la izquierda es más reciente Files that exist on both sides, right one is newer @@ -358,6 +390,8 @@ Files/folders that exist on left side only Ficheros/carpetas que existen sólo en el lado izquierdo Files/folders that exist on right side only Ficheros/carpetas que existen sólo en el lado derecho +Filter + Filter active: Press again to deactivate Filtro activo: Clique aquí para desactivar Filter files @@ -380,8 +414,8 @@ FreeFileSync configuration FreeFileSync configuración FreeFileSync is up to date! FreeFileSync está actualizado -Full name -Nombre completo +Full path + Generating file list... Generando lista de ficheros... Global settings @@ -390,6 +424,8 @@ Help Ayuda Hide all error and warning messages Ocultar todos los mensajes de error y aviso +Hide conflicts + Hide files that are different Ocultar ficheros diferentes Hide files that are equal @@ -402,6 +438,12 @@ Hide files that exist on left side only Ocultar los ficheros que existen sólo en el lado izquierdo Hide files that exist on right side only Ocultar los ficheros que existen sólo en el lado derecho +Hide files that will be copied to the left side + +Hide files that will be copied to the right side + +Hide files that won't be copied + Hide filtered items Ocultar items filtrados Hide further error messages during the current process @@ -414,6 +456,8 @@ Homepage Homepage If you like FFS Si te gusta FFS +Ignore 1-hour file time difference + Ignore errors Ignorar errores Ignore subsequent errors @@ -426,8 +470,8 @@ Include Incluir Include temporarily Incluir temporalmente -Include: *.doc;*.zip;*.exe\nExclude: *\\temp\\* -Incluir: *.doc;*.zip;*.exe\nExcluir: *\\temp\\* +Include: *.doc;*.zip;*.exe\nExclude: \\temp\\* + Info Info Information @@ -436,24 +480,30 @@ Initialization of Recycle Bin failed! ¡El inicio de la Papelera falló! It was not possible to initialize the Recycle Bin!\n\nIt's likely that you are not using Windows.\nIf you want this feature included, please contact the author. :) ¡No fue posible iniciar la Papelera!\n\nEs probable que no esté usando Windows.\nSi quiere que este hecho sea considerado, por favor, contactate con el autor :) -Legend -Leyenda +Left: + Load configuration from file Cargar configuración desde fichero Load configuration history (press DEL to delete items) Cargar histórico de configuración (presionar DEL para borrar elementos) Log-messages: Log de mensajes: +Logging + Mirror ->> Espejo ->> Mirror backup of left folder: Right folder will be overwritten and exactly match left folder after synchronization. Backup espejo de la carpeta de la izquierda: La carpeta de la derecha será sustituída y coincidirá exactamente con la carpeta de la izquierda después de la sincronización. +More than 50% of the total number of files will be copied or deleted! + Move column down Mover columna abajo Move column up Mover columna arriba -Not all items were synchronized! Have a look at the list. -¡No todos los elementos fueron sincronizados! Por favor, verifique la lista. +Not all items have been synchronized! Have a look at the list. + +Not enough free disk space available in: + Nothing to synchronize according to configuration! ¡No hay nada que sincronizar de acuerdo con la configuración! Number of files and directories that will be created @@ -464,18 +514,20 @@ Number of files that will be overwritten Número de ficheros que serán sustituídos OK OK -Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the full name including path prefix. -Sólo los ficheros/directorios que pasen el filtro serán seleccionados para la sincronización. El filtro se aplicará al nombre completo, incluído el camino. -Open synchronization dialog -Abrir diálogo de sincronización +Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the name relative(!) to the synchronization directories. + Open with File Manager\tD-Click Abrir con el Explorador\tD-Click Operation aborted! Operación abortada! Operation: Operación: +Overview + Pause Pausa +Paused + Please fill all empty directory fields. Por favor, rellene todos los campos del directorio vacíos. Press button to activate filter @@ -484,6 +536,8 @@ Preview Previsualizar Published under the GNU General Public License: Publicado bajo "GNU General Public License": +Question + Quit Salir Relative path @@ -492,16 +546,20 @@ Remove folder pair Eliminar par de carpetas Reset Reiniciar +Reset all warning messages + Reset all warning messages? ¿Reiniciar todos los mensajes de aviso? -Resets all warning messages -Reinicia todos los mensajes de aviso Result Resultado +Right: + S&ave configuration G&uardar configuración -Save aborted! -¡Guardar abortado! +S&witch view + +Save changes to current configuration? + Save current configuration to file Guardar la configuración actual en un fichero Scanning... @@ -510,8 +568,14 @@ Scanning: Analizar: Select a folder Seleccione una carpeta +Select logfile directory: + Select variant: Sleccione una variante: +Show conflicts + +Show file icons + Show files that are different Mostrar los ficheros diferentes Show files that are equal @@ -524,10 +588,18 @@ Show files that exist on left side only Mostrar ficheros existentes en la izquierda sólamente Show files that exist on right side only Mostrar ficheros existentes en la derecha sólamente +Show files that will be copied to the left side + +Show files that will be copied to the right side + +Show files that won't be copied + Show popup Mostrar "popups" Show popup on errors or warnings Mostrar "popup" de errores o avisos +Significant difference detected: + Silent mode Modo silencioso Size @@ -536,6 +608,8 @@ Sorting file list... Ordenar lista de ficheros... Source code written completely in C++ utilizing: Código fuente escrito en C++ utilizando: +Speed: + Start Iniciar Start synchronization @@ -544,6 +618,8 @@ Stop Parar Swap sides Intercambiar lados +Synchronization Preview + Synchronization aborted! Sincronización abortada! Synchronization completed successfully! @@ -556,8 +632,8 @@ Synchronization settings Parámetros de sincronización Synchronization status Estado de la sincronización -Synchronize all .doc, .zip and .exe files except everything from folder \"temp\". -Sincronizar todos los ficheros .doc, .zip and .exe excepto los de la carpeta \"temp\". +Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\". + Synchronize both sides simultaneously: Copy new or updated files in both directions. Sincronizar ambos lados simultáneamente: Copiar ficheros nuevos o actualizados en ambas direcciones. Synchronizing... @@ -576,10 +652,16 @@ Time Hora Time elapsed: Tiempo transcurrido: +Time remaining: + Total amount of data that will be transferred Cantidad total de datos que serán transferidos +Total required free disk space: + Total time: Tiempo total: +Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes. + Two way <-> Doble sentido <-> Unable to connect to sourceforge.net! @@ -590,10 +672,10 @@ Unable to initialize Recycle Bin! Permitir iniciar la Papelera Uncheck all Deseleccionar todos +Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization. + Update -> Actualizar -> -Update: -Actualizar: Use Recycle Bin Utilizar la Papelera Use Recycle Bin when deleting or overwriting files during synchronization @@ -612,6 +694,8 @@ different ficheros diferentes file exists on both sides el fichero existe en ambos lados +flash conflict\n + on one side only fichero sólo en un lado |> file on right side only\n @@ -1,4 +1,4 @@ -FreeFileSync v1.18 +FreeFileSync v1.19 ------------------ Usage @@ -13,7 +13,7 @@ Key Features 2. No limitations: An arbitrary number of files can be synchronized. 3. Unicode support. 4. Network support. -5. Full support for Windows/Linux symbolic links. +5. Full support for Windows/Linux Symbolic Links and Windows Junction Points. 6. Lean & easily accessible UI: Highly optimized for speed and huge sets of data. 7. Algorithms coded in C++ completely. 8. Progress indicators are updated only every 100ms for optimal performance! @@ -82,6 +82,16 @@ You can: - drag & drop any directory onto the main window to set the directory f - drag & drop *.ffs_batch files onto the main window to display and edit the batch configuration - drag & drop *.ffs_batch files onto the batch dialog to display and edit the batch configuration + +4.) Synchronize two folders but exclude all subfolders from synchronization + +Assuming you plan to synchronize two folders "C:\Source" and "D:\Target", you'll want to setup a filter like this: + + Include: * + Exclude: *\* + +This will exclude all files and folders within the two directories that contain a "\" character. These are exactly the subfolders and -files you want to exclude. + Links ------ diff --git a/Resources.dat b/Resources.dat Binary files differindex 86bd81fa..436e96e8 100644 --- a/Resources.dat +++ b/Resources.dat diff --git a/algorithm.cpp b/algorithm.cpp index c595bdd3..00c1e81f 100644 --- a/algorithm.cpp +++ b/algorithm.cpp @@ -148,78 +148,18 @@ void FreeFileSync::swapGrids(FolderComparison& folderCmp) else if (i->cmpResult == FILE_LEFT_NEWER) i->cmpResult = FILE_RIGHT_NEWER; + //swap sync direction + if (i->direction == SYNC_DIR_LEFT) + i->direction = SYNC_DIR_RIGHT; + else if (i->direction == SYNC_DIR_RIGHT) + i->direction = SYNC_DIR_LEFT; + //swap file descriptors std::swap(i->fileDescrLeft, i->fileDescrRight); } } } -/* -void FreeFileSync::adjustModificationTimes(const Zstring& parentDirectory, const int timeInSeconds, ErrorHandler* errorHandler) throw(AbortThisProcess) -{ -#ifndef __WXDEBUG__ - wxLogNull noWxLogs; //prevent wxWidgets logging -#endif - - if (timeInSeconds == 0) - return; - - std::vector<Zstring> fileList; - std::vector<Zstring> dirList; - - while (true) //should be executed in own scope so that directory access does not disturb deletion - { - try - { //get all files and folders from directory (and subdirectories) - FreeFileSync::getAllFilesAndDirs(parentDirectory, fileList, dirList); - break; - } - catch (const FileError& e) - { - ErrorHandler::Response rv = errorHandler->reportError(e.show()); - if (rv == ErrorHandler::IGNORE_ERROR) - break; - else if (rv == ErrorHandler::RETRY) - ; //continue with loop - else - assert (false); - } - } - - //this part is only a bit slower than direct Windows API-access! - wxDateTime modTime; - for (unsigned int j = 0; j < fileList.size(); ++j) - { - while (true) //own scope for directory access to not disturb file access! - { - try - { - wxFileName file(fileList[j].c_str()); - if (!file.GetTimes(NULL, &modTime, NULL)) //get modification time - throw FileError(Zstring(_("Error changing modification time:")) + wxT(" \"") + fileList[j] + wxT("\"")); - - modTime.Add(wxTimeSpan(0, 0, timeInSeconds, 0)); - - if (!file.SetTimes(NULL, &modTime, NULL)) //get modification time - throw FileError(Zstring(_("Error changing modification time:")) + wxT(" \"") + fileList[j] + wxT("\"")); - - break; - } - catch (const FileError& error) - { - ErrorHandler::Response rv = errorHandler->reportError(error.show()); - if (rv == ErrorHandler::IGNORE_ERROR) - break; - else if (rv == ErrorHandler::RETRY) - ; //continue with loop - else - assert (false); - } - } - } -} -*/ - //add(!) all files and subfolder gridlines that are dependent from the directory void FreeFileSync::addSubElements(const FileComparison& fileCmp, const FileCompareLine& relevantRow, std::set<int>& subElements) @@ -358,35 +298,44 @@ private: template <bool leftSide> //update compareGrid row information after deletion from leftSide (or !leftSide) inline -void updateCmpLineAfterDeletion(FileCompareLine& relevantRow, const int rowNr, RemoveAtExit& markForRemoval) +void updateCmpLineAfterDeletion(const int rowNr, const SyncConfiguration& syncConfig, FileComparison& fileCmp, RemoveAtExit& markForRemoval) { - FileDescrLine* fileDescr; //get descriptor for file to be deleted; evaluated at compile time - FileDescrLine* fileDescrPartner; //file descriptor for "other side" - if (leftSide) - { - fileDescr = &relevantRow.fileDescrLeft; - fileDescrPartner = &relevantRow.fileDescrRight; - } - else - { - fileDescr = &relevantRow.fileDescrRight; - fileDescrPartner = &relevantRow.fileDescrLeft; - } + //retrieve all files and subfolder gridlines that are dependent from this deleted entry + std::set<int> rowsToDelete; + rowsToDelete.insert(rowNr); + FreeFileSync::addSubElements(fileCmp, fileCmp[rowNr], rowsToDelete); - - //remove deleted entries from grid - if (fileDescrPartner->objType == FileDescrLine::TYPE_NOTHING) - markForRemoval.removeRow(rowNr); - else + //remove deleted entries from fileCmp (or adapt it if deleted from one side only) + for (std::set<int>::iterator j = rowsToDelete.begin(); j != rowsToDelete.end(); ++j) { - //initialize fileDescr for deleted file/folder - *fileDescr = FileDescrLine(); + FileCompareLine& currentLine = fileCmp[*j]; - //adapt the compare result - if (leftSide) //again evaluated at compile time - relevantRow.cmpResult = FILE_RIGHT_SIDE_ONLY; + //file descriptor for "other side" + const FileDescrLine* const fileDescrPartner = leftSide ? ¤tLine.fileDescrRight : ¤tLine.fileDescrLeft; + + //remove deleted entries from grid + if (fileDescrPartner->objType == FileDescrLine::TYPE_NOTHING) + markForRemoval.removeRow(*j); else - relevantRow.cmpResult = FILE_LEFT_SIDE_ONLY; + { + //get descriptor for file to be deleted; evaluated at compile time + FileDescrLine* const fileDescr = leftSide ? ¤tLine.fileDescrLeft : ¤tLine.fileDescrRight; + + //initialize fileDescr for deleted file/folder + *fileDescr = FileDescrLine(); + + //adapt the compare result and sync direction + if (leftSide) //again evaluated at compile time + { + currentLine.cmpResult = FILE_RIGHT_SIDE_ONLY; + currentLine.direction = syncConfig.exRightSideOnly; + } + else + { + currentLine.cmpResult = FILE_LEFT_SIDE_ONLY; + currentLine.direction = syncConfig.exLeftSideOnly; + } + } } } @@ -396,43 +345,32 @@ void deleteFromGridAndHDOneSide(FileComparison& fileCmp, const std::set<int>& rowsToDeleteOneSide, const bool useRecycleBin, RemoveAtExit& markForRemoval, + const SyncConfiguration& syncConfig, ErrorHandler* errorHandler) { for (std::set<int>::iterator i = rowsToDeleteOneSide.begin(); i != rowsToDeleteOneSide.end(); ++i) { - FileCompareLine& currentCmpLine = fileCmp[*i]; - - FileDescrLine* fileDescr = NULL; //get descriptor for file to be deleted; evaluated at compile time - if (leftSide) - fileDescr = ¤tCmpLine.fileDescrLeft; - else - fileDescr = ¤tCmpLine.fileDescrRight; + //get descriptor for file to be deleted; evaluated at compile time + const FileDescrLine* const fileDescr = leftSide ? &fileCmp[*i].fileDescrLeft : &fileCmp[*i].fileDescrRight; while (true) { try { - if (fileDescr->objType == FileDescrLine::TYPE_FILE) + switch (fileDescr->objType) + { + case FileDescrLine::TYPE_FILE: FreeFileSync::removeFile(fileDescr->fullName, useRecycleBin); - else if (fileDescr->objType == FileDescrLine::TYPE_DIRECTORY) + updateCmpLineAfterDeletion<leftSide>(*i, syncConfig, fileCmp, markForRemoval); //remove entries from fileCmp + break; + case FileDescrLine::TYPE_DIRECTORY: FreeFileSync::removeDirectory(fileDescr->fullName, useRecycleBin); - else if (fileDescr->objType == FileDescrLine::TYPE_NOTHING) - break; //nothing to do - else - { - assert(false); + updateCmpLineAfterDeletion<leftSide>(*i, syncConfig, fileCmp, markForRemoval); //remove entries from fileCmp + break; + case FileDescrLine::TYPE_NOTHING: break; } - //retrieve all files and subfolder gridlines that are dependent from this deleted entry - std::set<int> rowsToDelete; - rowsToDelete.insert(*i); - FreeFileSync::addSubElements(fileCmp, currentCmpLine, rowsToDelete); - - //remove deleted entries from fileCmp (or adapt it if deleted from one side only) - for (std::set<int>::iterator j = rowsToDelete.begin(); j != rowsToDelete.end(); ++j) - updateCmpLineAfterDeletion<leftSide>(fileCmp[*j], *j, markForRemoval); - break; } catch (const FileError& error) @@ -457,6 +395,7 @@ void FreeFileSync::deleteFromGridAndHD(FileComparison& fileCmp, const std::set<int>& rowsToDeleteOnRight, const bool deleteOnBothSides, const bool useRecycleBin, + const SyncConfiguration& syncConfig, ErrorHandler* errorHandler) { //remove deleted rows from fileCmp (AFTER all rows to be deleted are known: consider row references! @@ -473,12 +412,14 @@ void FreeFileSync::deleteFromGridAndHD(FileComparison& fileCmp, rowsToDeleteBothSides, useRecycleBin, markForRemoval, + syncConfig, errorHandler); deleteFromGridAndHDOneSide<false>(fileCmp, rowsToDeleteBothSides, useRecycleBin, markForRemoval, + syncConfig, errorHandler); } else @@ -487,12 +428,14 @@ void FreeFileSync::deleteFromGridAndHD(FileComparison& fileCmp, rowsToDeleteOnLeft, useRecycleBin, markForRemoval, + syncConfig, errorHandler); deleteFromGridAndHDOneSide<false>(fileCmp, rowsToDeleteOnRight, useRecycleBin, markForRemoval, + syncConfig, errorHandler); } } @@ -528,11 +471,12 @@ void writeFourDigitNumber(unsigned int number, wxChar*& position) } -wxString FreeFileSync::utcTimeToLocalString(const wxLongLong& utcTime) +wxString FreeFileSync::utcTimeToLocalString(const wxLongLong& utcTime, const Zstring& filename) { #ifdef FFS_WIN //convert ansi C time to FILETIME wxLongLong fileTimeLong(utcTime); + fileTimeLong += wxLongLong(2, 3054539008UL); //timeshift between ansi C time and FILETIME in seconds == 11644473600s fileTimeLong *= 10000000; @@ -540,19 +484,29 @@ wxString FreeFileSync::utcTimeToLocalString(const wxLongLong& utcTime) lastWriteTimeUtc.dwLowDateTime = fileTimeLong.GetLo(); //GetLo() returns unsigned lastWriteTimeUtc.dwHighDateTime = unsigned(fileTimeLong.GetHi()); //GetHi() returns signed + FILETIME localFileTime; - if (FileTimeToLocalFileTime( //convert to local time + if (::FileTimeToLocalFileTime( //convert to local time &lastWriteTimeUtc, //pointer to UTC file time to convert &localFileTime //pointer to converted file time ) == 0) - throw RuntimeException(wxString(_("Conversion error:")) + wxT(" FILETIME -> local FILETIME")); + throw RuntimeException(wxString(_("Conversion error:")) + wxT(" FILETIME -> local FILETIME: ") + + wxT("(") + wxULongLong(lastWriteTimeUtc.dwHighDateTime, lastWriteTimeUtc.dwLowDateTime).ToString() + wxT(") ") + + filename.c_str() + wxT("\n\n") + getLastErrorFormatted().c_str()); + + if (localFileTime.dwHighDateTime > 2147483647) //== 256^4 / 2 - 1 == 0x7fffffff + return _("Error"); //this actually CAN happen if UTC time is just below this border and ::FileTimeToLocalFileTime() adds 2 hours due to DST or whatever! + //Testcase (UTC): dateHigh = 2147483647 -> year 30000 + // dateLow = 4294967295 SYSTEMTIME time; - if (FileTimeToSystemTime( + if (::FileTimeToSystemTime( &localFileTime, //pointer to file time to convert &time //pointer to structure to receive system time ) == 0) - throw RuntimeException(wxString(_("Conversion error:")) + wxT(" FILETIME -> SYSTEMTIME")); + throw RuntimeException(wxString(_("Conversion error:")) + wxT(" local FILETIME -> SYSTEMTIME: ") + + wxT("(") + wxULongLong(localFileTime.dwHighDateTime, localFileTime.dwLowDateTime).ToString() + wxT(") ") + + filename.c_str() + wxT("\n\n") + getLastErrorFormatted().c_str()); //assemble time string (performance optimized) wxChar formattedTime[21]; @@ -589,10 +543,8 @@ wxString FreeFileSync::utcTimeToLocalString(const wxLongLong& utcTime) #ifdef FFS_WIN Zstring FreeFileSync::getLastErrorFormatted(const unsigned long lastError) //try to get additional Windows error information { - unsigned long lastErrorCode = lastError; - //determine error code if none was specified - if (lastErrorCode == 0) - lastErrorCode = GetLastError(); + //determine error code if none was specified + const unsigned long lastErrorCode = lastError == 0 ? GetLastError() : lastError; Zstring output = Zstring(wxT("Windows Error Code ")) + wxString::Format(wxT("%u"), lastErrorCode).c_str(); @@ -605,10 +557,8 @@ Zstring FreeFileSync::getLastErrorFormatted(const unsigned long lastError) //try #elif defined FFS_LINUX Zstring FreeFileSync::getLastErrorFormatted(const int lastError) //try to get additional Linux error information { - int lastErrorCode = lastError; //determine error code if none was specified - if (lastErrorCode == 0) - lastErrorCode = errno; + const int lastErrorCode = lastError == 0 ? errno : lastError; Zstring output = Zstring(wxT("Linux Error Code ")) + wxString::Format(wxT("%i"), lastErrorCode).c_str(); output += Zstring(wxT(": ")) + strerror(lastErrorCode); diff --git a/algorithm.h b/algorithm.h index 9cf1e8ad..f05eb95d 100644 --- a/algorithm.h +++ b/algorithm.h @@ -32,10 +32,11 @@ namespace FreeFileSync const std::set<int>& rowsToDeleteOnRight, const bool deleteOnBothSides, const bool useRecycleBin, + const SyncConfiguration& syncConfig, ErrorHandler* errorHandler); - wxString utcTimeToLocalString(const wxLongLong& utcTime); + wxString utcTimeToLocalString(const wxLongLong& utcTime, const Zstring& filename); //enhanced binary search template: returns an iterator template <class ForwardIterator, class T> diff --git a/comparison.cpp b/comparison.cpp index 8a092935..253b3d81 100644 --- a/comparison.cpp +++ b/comparison.cpp @@ -10,6 +10,8 @@ #include <memory> #include "library/statusHandler.h" #include "library/fileHandling.h" +#include "synchronization.h" +#include "library/filter.h" #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" @@ -21,10 +23,11 @@ using namespace FreeFileSync; class GetAllFilesFull : public FullDetailFileTraverser { public: - GetAllFilesFull(DirectoryDescrType& output, const Zstring& dirThatIsSearched, StatusHandler* handler) : + GetAllFilesFull(DirectoryDescrType& output, const Zstring& dirThatIsSearched, const FilterProcess* filter, StatusHandler* handler) : m_output(output), directory(dirThatIsSearched), textScanning(Zstring(_("Scanning:")) + wxT(" \n")), + filterInstance(filter), statusHandler(handler) { prefixLength = directory.length(); @@ -41,6 +44,10 @@ public: wxDirTraverseResult OnFile(const Zstring& fullFileName, const FileInfo& details) //virtual impl. { + //apply filter before processing (use relative name!) + if (filterInstance && !filterInstance->matchesFileFilter(fullFileName.c_str() + prefixLength)) + return wxDIR_CONTINUE; + FileDescrLine fileDescr; fileDescr.fullName = fullFileName; fileDescr.relativeName = fullFileName.zsubstr(prefixLength); @@ -75,6 +82,10 @@ public: wxDirTraverseResult OnDir(const Zstring& fullDirName) //virtual impl. { + //apply filter before processing (use relative name!) + if (filterInstance && !filterInstance->matchesDirFilter(fullDirName.c_str() + prefixLength)) + return wxDIR_IGNORE; + #ifdef FFS_WIN if ( fullDirName.EndsWith(wxT("\\RECYCLER")) || fullDirName.EndsWith(wxT("\\System Volume Information"))) @@ -137,6 +148,7 @@ private: Zstring directory; int prefixLength; const Zstring textScanning; + const FilterProcess* const filterInstance; //may be NULL! StatusHandler* statusHandler; }; @@ -160,8 +172,9 @@ struct DescrBufferLine class DirectoryDescrBuffer //buffer multiple scans of the same directories { public: - DirectoryDescrBuffer(const bool traverseDirectorySymlinks, StatusHandler* statusUpdater) : + DirectoryDescrBuffer(const bool traverseDirectorySymlinks, const FilterProcess* filter, StatusHandler* statusUpdater) : m_traverseDirectorySymlinks(traverseDirectorySymlinks), + filterInstance(filter), m_statusUpdater(statusUpdater) {} ~DirectoryDescrBuffer() @@ -189,7 +202,7 @@ public: buffer.insert(bufferEntry); //exception safety: insert into buffer right after creation! //get all files and folders from directoryFormatted (and subdirectories) - GetAllFilesFull traverser(*bufferEntry.directoryDesc, directoryFormatted, m_statusUpdater); //exceptions may be thrown! + GetAllFilesFull traverser(*bufferEntry.directoryDesc, directoryFormatted, filterInstance, m_statusUpdater); //exceptions may be thrown! traverseInDetail(directoryFormatted, m_traverseDirectorySymlinks, &traverser); return bufferEntry.directoryDesc; @@ -200,6 +213,7 @@ private: std::set<DescrBufferLine> buffer; const bool m_traverseDirectorySymlinks; + const FilterProcess* const filterInstance; //may be NULL! StatusHandler* m_statusUpdater; }; @@ -276,16 +290,18 @@ bool foldersHaveDependencies(const std::vector<FolderPair>& folderPairs, wxStrin CompareProcess::CompareProcess(const bool traverseSymLinks, - const unsigned fileTimeTol, + const unsigned int fileTimeTol, + const bool ignoreOneHourDiff, bool& warningDependentFolders, + const FilterProcess* filter, //may be NULL StatusHandler* handler) : - traverseDirectorySymlinks(traverseSymLinks), fileTimeTolerance(fileTimeTol), + ignoreOneHourDifference(ignoreOneHourDiff), m_warningDependentFolders(warningDependentFolders), statusUpdater(handler), txtComparingContentOfFiles(Zstring(_("Comparing content of files %x")).Replace(wxT("%x"), wxT("\n\"%x\""), false)) { - descriptionBuffer = new DirectoryDescrBuffer(traverseSymLinks, handler); + descriptionBuffer = new DirectoryDescrBuffer(traverseSymLinks, filter, handler); } @@ -457,18 +473,9 @@ bool filesHaveSameContentUpdating(const Zstring& filename1, const Zstring& filen }*/ -inline -bool sameFileTime(const wxLongLong& a, const wxLongLong& b, const unsigned tolerance) -{ - if (a < b) - return b - a <= tolerance; - else - return a - b <= tolerance; -} - - void CompareProcess::startCompareProcess(const std::vector<FolderPair>& directoryPairs, const CompareVariant cmpVar, + const SyncConfiguration& config, FolderComparison& output) { #ifndef __WXDEBUG__ @@ -477,6 +484,9 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPair>& director //PERF_START; + //init process: keep at beginning so that all gui elements are initialized properly + statusUpdater->initNewProcess(-1, 0, StatusHandler::PROCESS_SCANNING); //it's not known how many files will be scanned => -1 objects + //format directory pairs: ensure they end with GlobalResources::FILE_NAME_SEPARATOR! std::vector<FolderPair> directoryPairsFormatted; for (std::vector<FolderPair>::const_iterator i = directoryPairs.begin(); i != directoryPairs.end(); ++i) @@ -484,7 +494,7 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPair>& director FolderPair(FreeFileSync::getFormattedDirectoryName(i->leftDirectory), FreeFileSync::getFormattedDirectoryName(i->rightDirectory))); - //some basic checks: + //-------------------some basic checks:------------------------------------------ //check if folders are valid wxString errorMessage; @@ -507,6 +517,9 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPair>& director } } + //-------------------end of basic checks------------------------------------------ + + try { FolderComparison output_tmp; //write to output not before END of process! @@ -520,7 +533,11 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPair>& director break; } - //only if everything was processed correctly output is written to! output mustn't change to be in sync with GUI grid view!!! + //actually this is the initial determination + FreeFileSync::redetermineSyncDirection(config, output_tmp); + + //only if everything was processed correctly output is written to! + //note: output mustn't change during this process to be in sync with GUI grid view!!! output_tmp.swap(output); } catch (const RuntimeException& theException) @@ -536,11 +553,21 @@ void CompareProcess::startCompareProcess(const std::vector<FolderPair>& director } -void CompareProcess::compareByTimeSize(const std::vector<FolderPair>& directoryPairsFormatted, FolderComparison& output) +const CompareFilesResult FILE_UNDEFINED = CompareFilesResult(42); + + +inline +bool sameFileTime(const wxLongLong& a, const wxLongLong& b, const unsigned tolerance) { - //inform about the total amount of data that will be processed from now on - statusUpdater->initNewProcess(-1, 0, StatusHandler::PROCESS_SCANNING); //it's not known how many files will be scanned => -1 objects + if (a < b) + return b - a <= tolerance; + else + return a - b <= tolerance; +} + +void CompareProcess::compareByTimeSize(const std::vector<FolderPair>& directoryPairsFormatted, FolderComparison& output) +{ //process one folder pair after each other for (std::vector<FolderPair>::const_iterator pair = directoryPairsFormatted.begin(); pair != directoryPairsFormatted.end(); ++pair) { @@ -557,20 +584,63 @@ void CompareProcess::compareByTimeSize(const std::vector<FolderPair>& directoryP for (FileComparison::iterator i = fileCmp.begin(); i != fileCmp.end(); ++i) if (i->cmpResult == FILE_UNDEFINED) { - //last write time may differ by up to 2 seconds (NTFS vs FAT32) - if (sameFileTime(i->fileDescrLeft.lastWriteTimeRaw, i->fileDescrRight.lastWriteTimeRaw, fileTimeTolerance)) + if (i->fileDescrLeft.lastWriteTimeRaw != i->fileDescrRight.lastWriteTimeRaw) { - if (i->fileDescrLeft.fileSize == i->fileDescrRight.fileSize) - i->cmpResult = FILE_EQUAL; - else - i->cmpResult = FILE_DIFFERENT; + //number of seconds since Jan 1st 1970 + 1 year (needn't be too precise) + static const long oneYearFromNow = wxGetUTCTime() + 365 * 24 * 3600; + + //check for erroneous dates (but only if dates are not (EXACTLY) the same) + if ( i->fileDescrLeft.lastWriteTimeRaw < 0 || //earlier than Jan 1st 1970 + i->fileDescrRight.lastWriteTimeRaw < 0 || //earlier than Jan 1st 1970 + i->fileDescrLeft.lastWriteTimeRaw > oneYearFromNow || //dated more than one year in future + i->fileDescrRight.lastWriteTimeRaw > oneYearFromNow) //dated more than one year in future + { + i->cmpResult = FILE_CONFLICT; + } + else //from this block on all dates are at least "valid" + { + //last write time may differ by up to 2 seconds (NTFS vs FAT32) + if (sameFileTime(i->fileDescrLeft.lastWriteTimeRaw, i->fileDescrRight.lastWriteTimeRaw, fileTimeTolerance)) + { + if (i->fileDescrLeft.fileSize == i->fileDescrRight.fileSize) + i->cmpResult = FILE_EQUAL; + else + i->cmpResult = FILE_CONFLICT; //same date, different filesize + } + else + { + //finally: DST +/- 1-hour check: test if time diff is exactly +/- 1-hour (respecting 2 second FAT precision) + if (ignoreOneHourDifference && sameFileTime(i->fileDescrLeft.lastWriteTimeRaw, i->fileDescrRight.lastWriteTimeRaw, 3600 + 2)) + { + //date diff < 1 hour is a conflict: it's not safe to determine which file is newer + if (sameFileTime(i->fileDescrLeft.lastWriteTimeRaw, i->fileDescrRight.lastWriteTimeRaw, 3600 - 2 - 1)) + { + i->cmpResult = FILE_CONFLICT; + } + else //exact +/- 1-hour detected: treat as equal + { + if (i->fileDescrLeft.fileSize == i->fileDescrRight.fileSize) + i->cmpResult = FILE_EQUAL; + else + i->cmpResult = FILE_CONFLICT; //same date, different filesize + } + } + else + { + if (i->fileDescrLeft.lastWriteTimeRaw < i->fileDescrRight.lastWriteTimeRaw) + i->cmpResult = FILE_RIGHT_NEWER; + else + i->cmpResult = FILE_LEFT_NEWER; + } + } + } } - else + else //same write time { - if (i->fileDescrLeft.lastWriteTimeRaw < i->fileDescrRight.lastWriteTimeRaw) - i->cmpResult = FILE_RIGHT_NEWER; + if (i->fileDescrLeft.fileSize == i->fileDescrRight.fileSize) + i->cmpResult = FILE_EQUAL; else - i->cmpResult = FILE_LEFT_NEWER; + i->cmpResult = FILE_CONFLICT; //same date, different filesize } } } @@ -625,9 +695,6 @@ void CompareProcess::compareByContent(const std::vector<FolderPair>& directoryPa { //PERF_START; - //inform about the total amount of data that will be processed from now on - statusUpdater->initNewProcess(-1, 0, StatusHandler::PROCESS_SCANNING); //it's not known how many files will be scanned => -1 objects - //process one folder pair after each other for (std::vector<FolderPair>::const_iterator pair = directoryPairsFormatted.begin(); pair != directoryPairsFormatted.end(); ++pair) { @@ -800,7 +867,7 @@ void CompareProcess::performBaseComparison(const FolderPair& pair, FileCompariso output.reserve(output.size() + unsigned(std::max(directoryLeft->size(), directoryRight->size()) * 1.2)); //begin base comparison - FileCompareLine newline; + FileCompareLine newline(FILE_UNDEFINED, SYNC_DIR_NONE, true); DirectoryDescrType::iterator j; for (DirectoryDescrType::const_iterator i = directoryLeft->begin(); i != directoryLeft->end(); ++i) { //find files/folders that exist in left file tree but not in right one diff --git a/comparison.h b/comparison.h index 0f4681e5..2ec212ab 100644 --- a/comparison.h +++ b/comparison.h @@ -9,19 +9,24 @@ class DirectoryDescrBuffer; namespace FreeFileSync { + class FilterProcess; + //class handling comparison process class CompareProcess { public: CompareProcess(const bool traverseSymLinks, const unsigned fileTimeTol, + const bool ignoreOneHourDiff, bool& warningDependentFolders, + const FilterProcess* filter, //may be NULL StatusHandler* handler); ~CompareProcess(); void startCompareProcess(const std::vector<FolderPair>& directoryPairs, const CompareVariant cmpVar, + const SyncConfiguration& config, FolderComparison& output); private: @@ -35,8 +40,9 @@ namespace FreeFileSync //buffer accesses to the same directories; useful when multiple folder pairs are used DirectoryDescrBuffer* descriptionBuffer; - const bool traverseDirectorySymlinks; - const unsigned fileTimeTolerance; //max allowed file time deviation + const unsigned int fileTimeTolerance; //max allowed file time deviation + const bool ignoreOneHourDifference; + bool& m_warningDependentFolders; StatusHandler* statusUpdater; diff --git a/library/CustomGrid.cpp b/library/CustomGrid.cpp index faa75b2d..048bc5e0 100644 --- a/library/CustomGrid.cpp +++ b/library/CustomGrid.cpp @@ -41,11 +41,14 @@ class CustomGridTable : public wxGridTableBase public: CustomGridTable(int initialRows = 0, int initialCols = 0) : //note: initialRows/initialCols MUST match with GetNumberRows()/GetNumberCols() at initialization!!! wxGridTableBase(), - COLOR_BLUE( 80, 110, 255), - COLOR_GREY( 212, 208, 200), - COLOR_LIGHT_RED( 235, 57, 61), - COLOR_LIGHT_BLUE( 63, 206, 233), - COLOR_LIGHT_GREEN(54, 218, 2), + COLOR_BLUE( 80, 110, 255), + COLOR_GREY( 212, 208, 200), + COLOR_CMP_RED( 249, 163, 165), + COLOR_CMP_BLUE( 144, 232, 246), + COLOR_CMP_GREEN( 147, 253, 159), + COLOR_SYNC_BLUE( 201, 203, 247), + COLOR_SYNC_GREEN(197, 248, 190), + COLOR_YELLOW( 247, 252, 62), gridDataView(NULL), lastNrRows(initialRows), lastNrCols(initialCols) {} @@ -54,7 +57,7 @@ public: virtual ~CustomGridTable() {} - void setGridDataTable(GridView* gridDataView) + void setGridDataTable(const GridView* gridDataView) { this->gridDataView = gridDataView; } @@ -185,17 +188,20 @@ public: protected: const wxColour COLOR_BLUE; const wxColour COLOR_GREY; - const wxColour COLOR_LIGHT_RED; - const wxColour COLOR_LIGHT_BLUE; - const wxColour COLOR_LIGHT_GREEN; + const wxColour COLOR_CMP_RED; + const wxColour COLOR_CMP_BLUE; + const wxColour COLOR_CMP_GREEN; + const wxColour COLOR_SYNC_BLUE; + const wxColour COLOR_SYNC_GREEN; + const wxColour COLOR_YELLOW; const GridView* gridDataView; //(very fast) access to underlying grid data :) private: virtual const wxColour& getRowColor(int row) = 0; //rows that are filtered out are shown in different color - int lastNrRows; - int lastNrCols; + int lastNrRows; + int lastNrCols; }; @@ -246,8 +252,8 @@ public: { switch (getTypeAtPos(col)) { - case xmlAccess::FULL_NAME: - return gridLine->fileDescrLeft.fullName.c_str(); + case xmlAccess::FULL_PATH: + return wxString(gridLine->fileDescrLeft.fullName.c_str()); case xmlAccess::FILENAME: return wxEmptyString; case xmlAccess::REL_PATH: @@ -264,8 +270,8 @@ public: { switch (getTypeAtPos(col)) { - case xmlAccess::FULL_NAME: - return gridLine->fileDescrLeft.fullName.c_str(); + case xmlAccess::FULL_PATH: + return wxString(gridLine->fileDescrLeft.fullName.c_str()).BeforeLast(GlobalResources::FILE_NAME_SEPARATOR); case xmlAccess::FILENAME: //filename return wxString(gridLine->fileDescrLeft.relativeName.c_str()).AfterLast(GlobalResources::FILE_NAME_SEPARATOR); case xmlAccess::REL_PATH: //relative path @@ -275,7 +281,7 @@ public: case xmlAccess::SIZE: //file size return globalFunctions::includeNumberSeparator(gridLine->fileDescrLeft.fileSize.ToString()); case xmlAccess::DATE: //date - return FreeFileSync::utcTimeToLocalString(gridLine->fileDescrLeft.lastWriteTimeRaw); + return FreeFileSync::utcTimeToLocalString(gridLine->fileDescrLeft.lastWriteTimeRaw, gridLine->fileDescrLeft.fullName); } } } @@ -315,8 +321,8 @@ public: { switch (getTypeAtPos(col)) { - case xmlAccess::FULL_NAME: - return gridLine->fileDescrRight.fullName.c_str(); + case xmlAccess::FULL_PATH: + return wxString(gridLine->fileDescrRight.fullName.c_str()); case xmlAccess::FILENAME: //filename return wxEmptyString; case xmlAccess::REL_PATH: //relative path @@ -333,8 +339,8 @@ public: { switch (getTypeAtPos(col)) { - case xmlAccess::FULL_NAME: - return gridLine->fileDescrRight.fullName.c_str(); + case xmlAccess::FULL_PATH: + return wxString(gridLine->fileDescrRight.fullName.c_str()).BeforeLast(GlobalResources::FILE_NAME_SEPARATOR); case xmlAccess::FILENAME: //filename return wxString(gridLine->fileDescrRight.relativeName.c_str()).AfterLast(GlobalResources::FILE_NAME_SEPARATOR); case xmlAccess::REL_PATH: //relative path @@ -344,7 +350,7 @@ public: case xmlAccess::SIZE: //file size return globalFunctions::includeNumberSeparator(gridLine->fileDescrRight.fileSize.ToString()); case xmlAccess::DATE: //date - return FreeFileSync::utcTimeToLocalString(gridLine->fileDescrRight.lastWriteTimeRaw); + return FreeFileSync::utcTimeToLocalString(gridLine->fileDescrRight.lastWriteTimeRaw, gridLine->fileDescrRight.fullName); } } } @@ -376,7 +382,9 @@ class CustomGridTableMiddle : public CustomGridTable { public: //middle grid is created (first wxWidgets internal call to GetNumberCols()) with one column - CustomGridTableMiddle() : CustomGridTable(0, GetNumberCols()) {} //attention: static binding to virtual GetNumberCols() in a Constructor! + CustomGridTableMiddle() : + CustomGridTable(0, GetNumberCols()), //attention: static binding to virtual GetNumberCols() in a Constructor! + syncPreviewActive(false) {} virtual int GetNumberCols() { @@ -388,35 +396,21 @@ public: return wxEmptyString; } - virtual wxString GetValue(int row, int col) { - const FileCompareLine* gridLine = getRawData(row); - if (gridLine) - { - switch (gridLine->cmpResult) - { - case FILE_LEFT_SIDE_ONLY: - return wxT("<|"); - case FILE_RIGHT_SIDE_ONLY: - return wxT("|>"); - case FILE_RIGHT_NEWER: - return wxT(">>"); - case FILE_LEFT_NEWER: - return wxT("<<"); - case FILE_DIFFERENT: - return wxT("!="); - case FILE_EQUAL: - return wxT("=="); - default: - assert (false); - return wxEmptyString; - } - } - //if data is not found: return wxEmptyString; } + void enableSyncPreview(bool value) + { + syncPreviewActive = value; + } + + bool syncPreviewIsActive() const + { + return syncPreviewActive; + } + private: virtual const wxColour& getRowColor(int row) //rows that are filtered out are shown in different color { @@ -426,23 +420,46 @@ private: //mark filtered rows if (!gridLine->selectedForSynchronization) return COLOR_BLUE; - else + + if (syncPreviewActive) //synchronization preview + { + switch (gridLine->direction) + { + case SYNC_DIR_LEFT: + return COLOR_SYNC_BLUE; + case SYNC_DIR_RIGHT: + return COLOR_SYNC_GREEN; + case SYNC_DIR_NONE: + return *wxWHITE; + case SYNC_UNRESOLVED_CONFLICT: + return COLOR_YELLOW; + } + } + else //comparison results view + { switch (gridLine->cmpResult) { case FILE_LEFT_SIDE_ONLY: case FILE_RIGHT_SIDE_ONLY: - return COLOR_LIGHT_GREEN; + return COLOR_CMP_GREEN; case FILE_LEFT_NEWER: case FILE_RIGHT_NEWER: - return COLOR_LIGHT_BLUE; + return COLOR_CMP_BLUE; case FILE_DIFFERENT: - return COLOR_LIGHT_RED; - default: + return COLOR_CMP_RED; + case FILE_EQUAL: return *wxWHITE; + case FILE_CONFLICT: + return COLOR_YELLOW; } + } } + + //fallback return *wxWHITE; } + + bool syncPreviewActive; //determines wheter grid shall show compare result or sync preview }; //######################################################################################################## @@ -748,6 +765,59 @@ void CustomGrid::DrawColLabel(wxDC& dc, int col) dc.DrawBitmap(*sortMarker, GetColRight(col) - 16 - 2, 2, true); //respect 2-pixel border } + +std::set<int> CustomGrid::getAllSelectedRows() const +{ + std::set<int> output; + + const wxArrayInt selectedRows = this->GetSelectedRows(); + if (!selectedRows.IsEmpty()) + { + for (unsigned int i = 0; i < selectedRows.GetCount(); ++i) + output.insert(selectedRows[i]); + } + + if (!this->GetSelectedCols().IsEmpty()) //if a column is selected this is means all rows are marked for deletion + { + for (int k = 0; k < const_cast<CustomGrid*>(this)->GetNumberRows(); ++k) //messy wxGrid implementation... + output.insert(k); + } + + const wxGridCellCoordsArray singlySelected = this->GetSelectedCells(); + if (!singlySelected.IsEmpty()) + { + for (unsigned int k = 0; k < singlySelected.GetCount(); ++k) + output.insert(singlySelected[k].GetRow()); + } + + const wxGridCellCoordsArray tmpArrayTop = this->GetSelectionBlockTopLeft(); + if (!tmpArrayTop.IsEmpty()) + { + wxGridCellCoordsArray tmpArrayBottom = this->GetSelectionBlockBottomRight(); + + unsigned int arrayCount = tmpArrayTop.GetCount(); + + if (arrayCount == tmpArrayBottom.GetCount()) + { + for (unsigned int i = 0; i < arrayCount; ++i) + { + const int rowTop = tmpArrayTop[i].GetRow(); + const int rowBottom = tmpArrayBottom[i].GetRow(); + + for (int k = rowTop; k <= rowBottom; ++k) + output.insert(k); + } + } + } + + //some exception: also add current cursor row to selection if there are no others... hopefully improving usability + if (output.empty() && this->isLeadGrid()) + output.insert(const_cast<CustomGrid*>(this)->GetCursorRow()); //messy wxGrid implementation... + + return output; +} + + //############################################################################################ //CustomGrid specializations @@ -837,6 +907,26 @@ private: const CustomGridTableRim* const m_gridDataTable; }; +//---------------------------------------------------------------------------------------- + + +void CustomGridRim::initSettings(const bool showFileIcons, + CustomGrid* gridLeft, + CustomGrid* gridRight, + CustomGrid* gridMiddle, + const GridView* gridDataView) +{ + //these grids will scroll together + m_gridLeft = gridLeft; + m_gridRight = gridRight; + m_gridMiddle = gridMiddle; + + //set underlying grid data + assert(gridDataTable); + gridDataTable->setGridDataTable(gridDataView); + + enableFileIcons(showFileIcons); +} void CustomGridRim::updateGridSizes() @@ -851,7 +941,7 @@ xmlAccess::ColumnAttributes CustomGridRim::getDefaultColumnAttributes() xmlAccess::ColumnAttributes defaultColumnSettings; xmlAccess::ColumnAttrib newEntry; - newEntry.type = xmlAccess::FULL_NAME; + newEntry.type = xmlAccess::FULL_PATH; newEntry.visible = false; newEntry.position = 0; newEntry.width = 150; @@ -990,8 +1080,8 @@ wxString CustomGridRim::getTypeName(xmlAccess::ColumnTypes colType) { switch (colType) { - case xmlAccess::FULL_NAME: - return _("Full name"); + case xmlAccess::FULL_PATH: + return _("Full path"); case xmlAccess::FILENAME: return _("Filename"); case xmlAccess::REL_PATH: @@ -1002,13 +1092,14 @@ wxString CustomGridRim::getTypeName(xmlAccess::ColumnTypes colType) return _("Size"); case xmlAccess::DATE: return _("Date"); - default: - return wxEmptyString; } -} + return wxEmptyString; //dummy +} //---------------------------------------------------------------------------------------- + + CustomGridLeft::CustomGridLeft(wxWindow *parent, wxWindowID id, const wxPoint& pos, @@ -1029,25 +1120,14 @@ bool CustomGridLeft::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectio } -void CustomGridLeft::initSettings(const bool showFileIcons, - CustomGrid* gridLeft, - CustomGrid* gridRight, - CustomGrid* gridMiddle, - GridView* gridDataView) +void CustomGridLeft::enableFileIcons(const bool value) { - //these grids will scroll together - m_gridLeft = gridLeft; - m_gridRight = gridRight; - m_gridMiddle = gridMiddle; - - //set underlying grid data - assert(gridDataTable); - gridDataTable->setGridDataTable(gridDataView); - - if (showFileIcons) + if (value) SetDefaultRenderer(new GridCellRenderer<true, true>(gridDataTable)); //SetDefaultRenderer takes ownership! else SetDefaultRenderer(new GridCellRenderer<true, false>(gridDataTable)); + + Refresh(); } @@ -1085,25 +1165,14 @@ bool CustomGridRight::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelecti } -void CustomGridRight::initSettings(const bool showFileIcons, - CustomGrid* gridLeft, - CustomGrid* gridRight, - CustomGrid* gridMiddle, - GridView* gridDataView) +void CustomGridRight::enableFileIcons(const bool value) { - //these grids will scroll together - m_gridLeft = gridLeft; - m_gridRight = gridRight; - m_gridMiddle = gridMiddle; - - //set underlying grid data - assert(gridDataTable); - gridDataTable->setGridDataTable(gridDataView); - - if (showFileIcons) + if (value) SetDefaultRenderer(new GridCellRenderer<false, true>(gridDataTable)); //SetDefaultRenderer takes ownership! else SetDefaultRenderer(new GridCellRenderer<false, false>(gridDataTable)); + + Refresh(); } @@ -1123,6 +1192,19 @@ void CustomGridRight::DoPrepareDC(wxDC& dc) //---------------------------------------------------------------------------------------- +//define new event types +const wxEventType FFS_CHECK_ROWS_EVENT = wxNewEventType(); //attention! do NOT place in header to keep (generated) id unique! +const wxEventType FFS_SYNC_DIRECTION_EVENT = wxNewEventType(); + +const int CHECK_BOX_IMAGE = 11; //width of checkbox image +const int CHECK_BOX_WIDTH = CHECK_BOX_IMAGE + 3; //width of first block + +// cell: +// ---------------------------------- +// | checkbox | left | middle | right| +// ---------------------------------- + + CustomGridMiddle::CustomGridMiddle(wxWindow *parent, wxWindowID id, const wxPoint& pos, @@ -1130,25 +1212,155 @@ CustomGridMiddle::CustomGridMiddle(wxWindow *parent, long style, const wxString& name) : CustomGrid(parent, id, pos, size, style, name), + selectionRowBegin(-1), + selectionPos(BLOCKPOS_CHECK_BOX), + highlightedRow(-1), + highlightedPos(BLOCKPOS_CHECK_BOX), gridDataTable(NULL) { - const wxString header = _("Legend"); - wxString toolTip = header + wxT("\n") + - wxString().Pad(header.Len(), wxChar('-')) + wxT("\n") + - _("<| file on left side only\n") + - _("|> file on right side only\n") + - _("<< left file is newer\n") + - _(">> right file is newer\n") + - _("!= files are different\n") + - _("== files are equal\n\n"); - GetGridWindow()->SetToolTip(toolTip); + //connect events for dynamic selection of sync direction + GetGridWindow()->Connect(wxEVT_MOTION, wxMouseEventHandler(CustomGridMiddle::OnMouseMovement), NULL, this); + + GetGridWindow()->Connect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(CustomGridMiddle::OnLeaveWindow), NULL, this); + GetGridWindow()->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(CustomGridMiddle::OnLeftMouseUp), NULL, this); + GetGridWindow()->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(CustomGridMiddle::OnLeftMouseDown), NULL, this); +} + + +void CustomGridMiddle::OnMouseMovement(wxMouseEvent& event) +{ + const int highlightedRowOld = highlightedRow; + + if (selectionRowBegin == -1) //change highlightning only if currently not dragging mouse + { + highlightedRow = mousePosToRow(event.GetPosition(), &highlightedPos); + if (highlightedRow >= 0) RefreshRow(highlightedRow); + if ( highlightedRowOld >= 0 && + highlightedRow != highlightedRowOld) + RefreshRow(highlightedRowOld); + } + + event.Skip(); +} + + +void CustomGridMiddle::RefreshRow(int row) +{ + wxRect rectScrolled(CellToRect(row, 0)); + CalcScrolledPosition(rectScrolled.x, rectScrolled.y, &rectScrolled.x, &rectScrolled.y); + + GetGridWindow()->Refresh(false, &rectScrolled); //note: CellToRect() and YToRow work on m_gridWindow NOT on the whole grid! +} + + +void CustomGridMiddle::OnLeaveWindow(wxMouseEvent& event) +{ + highlightedRow = -1; + highlightedPos = BLOCKPOS_CHECK_BOX; + Refresh(); +} + + +void CustomGridMiddle::OnLeftMouseDown(wxMouseEvent& event) +{ + selectionRowBegin = mousePosToRow(event.GetPosition(), &selectionPos); + event.Skip(); +} + + +void CustomGridMiddle::OnLeftMouseUp(wxMouseEvent& event) +{ + const int rowEndFiltering = mousePosToRow(event.GetPosition()); + + if (0 <= selectionRowBegin && 0 <= rowEndFiltering) + { + switch (selectionPos) + { + case BLOCKPOS_CHECK_BOX: + { + //create a custom event + FFSCheckRowsEvent evt(selectionRowBegin, rowEndFiltering); + AddPendingEvent(evt); + } + break; + case BLOCKPOS_LEFT: + { + //create a custom event + FFSSyncDirectionEvent evt(selectionRowBegin, rowEndFiltering, SYNC_DIR_LEFT); + AddPendingEvent(evt); + } + break; + case BLOCKPOS_MIDDLE: + { + //create a custom event + FFSSyncDirectionEvent evt(selectionRowBegin, rowEndFiltering, SYNC_DIR_NONE); + AddPendingEvent(evt); + } + break; + case BLOCKPOS_RIGHT: + { + //create a custom event + FFSSyncDirectionEvent evt(selectionRowBegin, rowEndFiltering, SYNC_DIR_RIGHT); + AddPendingEvent(evt); + } + break; + } + } + selectionRowBegin = -1; + selectionPos = BLOCKPOS_CHECK_BOX; + + ClearSelection(); + event.Skip(); +} + + +int CustomGridMiddle::mousePosToRow(const wxPoint pos, BlockPosition* block) +{ + int row = -1; + int x = -1; + int y = -1; + CalcUnscrolledPosition( pos.x, pos.y, &x, &y ); + if (x >= 0 && y >= 0) + { + row = YToRow(y); + + //determine blockposition within cell (optional) + if (block) + { + *block = BLOCKPOS_CHECK_BOX; //default + if (gridDataTable->syncPreviewIsActive() && + row >= 0) + { + // cell: + // ---------------------------------- + // | checkbox | left | middle | right| + // ---------------------------------- + + const wxRect rect = CellToRect(row, 0); + if (rect.GetWidth() > CHECK_BOX_WIDTH) + { + const double blockWidth = (rect.GetWidth() - CHECK_BOX_WIDTH) / 3.0; + if (rect.GetX() + CHECK_BOX_WIDTH <= x && x < rect.GetX() + rect.GetWidth()) + { + if (x - (rect.GetX() + CHECK_BOX_WIDTH) < blockWidth) + *block = BLOCKPOS_LEFT; + else if (x - (rect.GetX() + CHECK_BOX_WIDTH) < 2 * blockWidth) + *block = BLOCKPOS_MIDDLE; + else + *block = BLOCKPOS_RIGHT; + } + } + } + } + } + return row; } void CustomGridMiddle::initSettings(CustomGrid* gridLeft, CustomGrid* gridRight, CustomGrid* gridMiddle, - FreeFileSync::GridView* gridDataView) + const FreeFileSync::GridView* gridDataView) { //these grids will scroll together m_gridLeft = gridLeft; @@ -1174,6 +1386,40 @@ void CustomGridMiddle::SetScrollbar(int orientation, int position, int thumbSize } #endif + +void CustomGridMiddle::enableSyncPreview(bool value) +{ + assert(gridDataTable); + gridDataTable->enableSyncPreview(value); + + //update legend + wxString toolTip; + + if (gridDataTable->syncPreviewIsActive()) //synchronization preview + { + const wxString header = _("Synchronization Preview"); + toolTip = header + wxT("\n") + wxString().Pad(header.Len(), wxChar('-')) + wxT("\n"); + toolTip += wxString(_("<- copy to left side\n")) + + _("-> copy to right side\n") + + wxT(" ")+ _("- do not copy\n") + + _("flash conflict\n"); + } + else //compare results view + { + const wxString header = _("Comparison Result"); + toolTip = header + wxT("\n") + wxString().Pad(header.Len(), wxChar('-')) + wxT("\n"); + toolTip += wxString(_("<| file on left side only\n")) + + _("|> file on right side only\n") + + _("<< left file is newer\n") + + _(">> right file is newer\n") + + _("!= files are different\n") + + _("== files are equal\n") + + _("flash conflict\n"); + } + GetGridColLabelWindow()->SetToolTip(toolTip); +} + + void CustomGridMiddle::updateGridSizes() { assert(gridDataTable); @@ -1184,7 +1430,7 @@ void CustomGridMiddle::updateGridSizes() class GridCellRendererMiddle : public wxGridCellStringRenderer { public: - GridCellRendererMiddle(CustomGridTable* gridDataTable) : m_gridDataTable(gridDataTable) {}; + GridCellRendererMiddle(const CustomGridMiddle* middleGrid) : m_gridMiddle(middleGrid) {}; virtual void Draw(wxGrid& grid, @@ -1195,36 +1441,112 @@ public: bool isSelected) { //retrieve grid data - const FileCompareLine* rowData = m_gridDataTable->getRawData(row); - if (!rowData) //no valid row + const FileCompareLine* const rowData = m_gridMiddle->gridDataTable->getRawData(row); + if (rowData) //no valid row { - wxGridCellStringRenderer::Draw(grid, attr, dc, rect, row, col, isSelected); - return; - } + if (rect.GetWidth() > CHECK_BOX_WIDTH) + { + wxRect rectShrinked(rect); - const int shift = std::min(11 + 3, rect.GetWidth()); //11 is width of checkbox image + //clean first block of rect that will receive image of checkbox + rectShrinked.SetWidth(CHECK_BOX_WIDTH); + wxGridCellRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected); - wxRect rectShrinked(rect); + //print image into first block + rectShrinked.SetX(rect.GetX() + 1); + bool selected = rowData->selectedForSynchronization; - //clean first block of rect that will receive image of checkbox - rectShrinked.SetWidth(shift); - wxGridCellRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected); + //HIGHLIGHTNING: + if ( row == m_gridMiddle->highlightedRow && + m_gridMiddle->highlightedPos == CustomGridMiddle::BLOCKPOS_CHECK_BOX) + selected = !selected; - //print image into first block - rectShrinked.SetX(rect.GetX() + 1); - if (rowData->selectedForSynchronization) - dc.DrawLabel(wxEmptyString, *globalResource.bitmapCheckBoxTrue, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); - else - dc.DrawLabel(wxEmptyString, *globalResource.bitmapCheckBoxFalse, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + if (selected) + dc.DrawLabel(wxEmptyString, *globalResource.bitmapCheckBoxTrue, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + else + dc.DrawLabel(wxEmptyString, *globalResource.bitmapCheckBoxFalse, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); - //print second block (default): display compare result - rectShrinked.SetWidth(rect.GetWidth() - shift); - rectShrinked.SetX(rect.GetX() + shift); - wxGridCellStringRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected); + //clean remaining block of rect that will receive image of checkbox/directions + rectShrinked.SetWidth(rect.GetWidth() - CHECK_BOX_WIDTH); + rectShrinked.SetX(rect.GetX() + CHECK_BOX_WIDTH); + wxGridCellRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected); + + //print remaining block + if (m_gridMiddle->gridDataTable->syncPreviewIsActive()) //synchronization preview + { + //print sync direction into second block + + //HIGHLIGHTNING: + if (row == m_gridMiddle->highlightedRow && m_gridMiddle->highlightedPos != CustomGridMiddle::BLOCKPOS_CHECK_BOX) + switch (m_gridMiddle->highlightedPos) + { + case CustomGridMiddle::BLOCKPOS_CHECK_BOX: + break; + case CustomGridMiddle::BLOCKPOS_LEFT: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapSyncDirLeftSmall, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + break; + case CustomGridMiddle::BLOCKPOS_MIDDLE: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapSyncDirNoneSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case CustomGridMiddle::BLOCKPOS_RIGHT: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapSyncDirRightSmall, rectShrinked, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); + break; + } + else //default + switch (rowData->direction) + { + case SYNC_DIR_LEFT: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapSyncDirLeftSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case SYNC_DIR_RIGHT: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapSyncDirRightSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case SYNC_DIR_NONE: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapSyncDirNoneSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case SYNC_UNRESOLVED_CONFLICT: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapConflictSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + } + } + else //comparison results view + { + switch (rowData->cmpResult) + { + case FILE_LEFT_SIDE_ONLY: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapLeftOnlySmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case FILE_RIGHT_SIDE_ONLY: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapRightOnlySmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case FILE_LEFT_NEWER: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapLeftNewerSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case FILE_RIGHT_NEWER: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapRightNewerSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case FILE_DIFFERENT: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapDifferentSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case FILE_EQUAL: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapEqualSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + case FILE_CONFLICT: + dc.DrawLabel(wxEmptyString, *globalResource.bitmapConflictSmall, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); + break; + } + } + + return; + } + } + + //fallback + wxGridCellStringRenderer::Draw(grid, attr, dc, rect, row, col, isSelected); } private: - const CustomGridTable* const m_gridDataTable; + const CustomGridMiddle* const m_gridMiddle; }; @@ -1234,7 +1556,7 @@ bool CustomGridMiddle::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelect SetTable(gridDataTable, true, wxGrid::wxGridSelectRows); //give ownership to wxGrid: gridDataTable is deleted automatically in wxGrid destructor //display checkboxes (representing bool values) if row is enabled for synchronization - SetDefaultRenderer(new GridCellRendererMiddle(gridDataTable)); //SetDefaultRenderer takes ownership! + SetDefaultRenderer(new GridCellRendererMiddle(this)); //SetDefaultRenderer takes ownership! return true; } diff --git a/library/CustomGrid.h b/library/CustomGrid.h index 802db231..89ec39d0 100644 --- a/library/CustomGrid.h +++ b/library/CustomGrid.h @@ -10,6 +10,7 @@ class CustomGridTable; class CustomGridTableRim; class CustomGridTableMiddle; +class GridCellRendererMiddle; namespace FreeFileSync { @@ -44,6 +45,8 @@ public: virtual void DrawColLabel(wxDC& dc, int col); + std::set<int> getAllSelectedRows() const; + //set sort direction indicator on UI void setSortMarker(const int sortColumn, const wxBitmap* bitmap = &wxNullBitmap); @@ -79,6 +82,12 @@ public: ~CustomGridRim() {} + void initSettings(const bool showFileIcons, //workaround: though this coding better belongs into a constructor + CustomGrid* gridLeft, //this is not possible due to source code generation (information not available at time of construction) + CustomGrid* gridRight, + CustomGrid* gridMiddle, + const FreeFileSync::GridView* gridDataView); + //notify wxGrid that underlying table size has changed void updateGridSizes(); @@ -88,9 +97,10 @@ public: void setColumnAttributes(const xmlAccess::ColumnAttributes& attr); xmlAccess::ColumnTypes getTypeAtPos(unsigned pos) const; - static wxString getTypeName(xmlAccess::ColumnTypes colType); + virtual void enableFileIcons(const bool value) = 0; + protected: CustomGridTableRim* gridDataTable; @@ -113,11 +123,7 @@ public: virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells); - void initSettings(const bool showFileIcons, //workaround: though this coding better belongs into a constructor - CustomGrid* gridLeft, //this is not possible due to source code generation (information not available at time of construction) - CustomGrid* gridRight, - CustomGrid* gridMiddle, - FreeFileSync::GridView* gridDataView); + virtual void enableFileIcons(const bool value); //this method is called when grid view changes: useful for parallel updating of multiple grids virtual void DoPrepareDC(wxDC& dc); @@ -138,11 +144,7 @@ public: virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells); - void initSettings(const bool showFileIcons, //workaround: though this coding better belongs into a constructor - CustomGrid* gridLeft, //this is not possible due to source code generation (information not available at time of construction) - CustomGrid* gridRight, - CustomGrid* gridMiddle, - FreeFileSync::GridView* gridDataView); + virtual void enableFileIcons(const bool value); //this method is called when grid view changes: useful for parallel updating of multiple grids virtual void DoPrepareDC(wxDC& dc); @@ -151,6 +153,8 @@ public: class CustomGridMiddle : public CustomGrid { + friend class GridCellRendererMiddle; + public: CustomGridMiddle(wxWindow *parent, wxWindowID id, @@ -166,7 +170,9 @@ public: void initSettings(CustomGrid* gridLeft, //workaround: though this coding better belongs into a constructor CustomGrid* gridRight, //this is not possible due to source code generation (information not available at time of construction) CustomGrid* gridMiddle, - FreeFileSync::GridView* gridDataView); + const FreeFileSync::GridView* gridDataView); + + void enableSyncPreview(bool value); //notify wxGrid that underlying table size has changed void updateGridSizes(); @@ -179,7 +185,90 @@ public: virtual void DoPrepareDC(wxDC& dc); private: + void OnMouseMovement(wxMouseEvent& event); + void OnLeaveWindow(wxMouseEvent& event); + void OnLeftMouseDown(wxMouseEvent& event); + void OnLeftMouseUp(wxMouseEvent& event); + + //small helper methods + void RefreshRow(int row); + enum BlockPosition //each cell can be divided into four blocks concerning mouse selections + { + BLOCKPOS_CHECK_BOX, + BLOCKPOS_LEFT, + BLOCKPOS_MIDDLE, + BLOCKPOS_RIGHT + }; + int mousePosToRow(const wxPoint pos, BlockPosition* block = NULL); + + //variables for selecting sync direction + int selectionRowBegin; + BlockPosition selectionPos; + + //variables for highlightning on mouse-over + int highlightedRow; + BlockPosition highlightedPos; + CustomGridTableMiddle* gridDataTable; }; +//custom events for middle grid: + +//-------------------------------------------------------------------------------------------- +//(UN-)CHECKING ROWS FROM SYNCHRONIZATION + +extern const wxEventType FFS_CHECK_ROWS_EVENT; //define new event type + +class FFSCheckRowsEvent : public wxCommandEvent +{ +public: + FFSCheckRowsEvent(const int from, const int to) : + wxCommandEvent(FFS_CHECK_ROWS_EVENT), + rowFrom(from), + rowTo(to) {} + + virtual wxEvent* Clone() const + { + return new FFSCheckRowsEvent(rowFrom, rowTo); + } + + const int rowFrom; + const int rowTo; +}; + +typedef void (wxEvtHandler::*FFSCheckRowsEventFunction)(FFSCheckRowsEvent&); + +#define FFSCheckRowsEventHandler(func) \ + (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(FFSCheckRowsEventFunction, &func) + +//-------------------------------------------------------------------------------------------- +//SELECTING SYNC DIRECTION + +extern const wxEventType FFS_SYNC_DIRECTION_EVENT; //define new event type + +class FFSSyncDirectionEvent : public wxCommandEvent +{ +public: + FFSSyncDirectionEvent(const int from, const int to, const FreeFileSync::SyncDirection dir) : + wxCommandEvent(FFS_SYNC_DIRECTION_EVENT), + rowFrom(from), + rowTo(to), + direction(dir) {} + + virtual wxEvent* Clone() const + { + return new FFSSyncDirectionEvent(rowFrom, rowTo, direction); + } + + const int rowFrom; + const int rowTo; + const FreeFileSync::SyncDirection direction; +}; + +typedef void (wxEvtHandler::*FFSSyncDirectionEventFunction)(FFSSyncDirectionEvent&); + +#define FFSSyncDirectionEventHandler(func) \ + (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(FFSSyncDirectionEventFunction, &func) + + #endif // CUSTOMGRID_H_INCLUDED diff --git a/library/customButton.cpp b/library/customButton.cpp index 02cfdad0..fc686d3f 100644 --- a/library/customButton.cpp +++ b/library/customButton.cpp @@ -126,6 +126,9 @@ void linearInterpolation(wxImage& img) wxBitmap wxButtonWithImage::createBitmapFromText(const wxString& text) { + if (text.empty()) + return wxBitmap(); + wxFont currentFont = wxBitmapButton::GetFont(); wxColor textColor = wxBitmapButton::GetForegroundColour(); diff --git a/library/fileHandling.cpp b/library/fileHandling.cpp index 4f8caec6..b6d3d9d7 100644 --- a/library/fileHandling.cpp +++ b/library/fileHandling.cpp @@ -284,18 +284,25 @@ private: }; +class KernelDllHandler //dynamically load windows API functions +{ + typedef DWORD WINAPI (*GetFinalPath)( + HANDLE hFile, + LPTSTR lpszFilePath, + DWORD cchFilePath, + DWORD dwFlags); -typedef DWORD WINAPI (*GetFinalPath)( - HANDLE hFile, - LPTSTR lpszFilePath, - DWORD cchFilePath, - DWORD dwFlags); +public: + static const KernelDllHandler& getInstance() //lazy creation of KernelDllHandler + { + static KernelDllHandler instance; + return instance; + } + GetFinalPath getFinalPathNameByHandle; -class DllHandler //dynamically load windows API functions -{ -public: - DllHandler() : +private: + KernelDllHandler() : getFinalPathNameByHandle(NULL), hKernel(NULL) { @@ -305,26 +312,15 @@ public: getFinalPathNameByHandle = reinterpret_cast<GetFinalPath>(::GetProcAddress(hKernel, "GetFinalPathNameByHandleW")); //load unicode version! } - ~DllHandler() + ~KernelDllHandler() { if (hKernel) ::FreeLibrary(hKernel); } - GetFinalPath getFinalPathNameByHandle; - -private: HINSTANCE hKernel; }; -inline -DllHandler& getDllHandler() //lazy creation of DllHandler -{ - static DllHandler instance; - return instance; -} - - Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target path of symbolic link to a directory { //open handle to target of symbolic link @@ -340,13 +336,13 @@ Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target pa CloseHandleOnExit dummy(hDir); - if (getDllHandler().getFinalPathNameByHandle == NULL ) + if (KernelDllHandler::getInstance().getFinalPathNameByHandle == NULL ) throw FileError(Zstring(_("Error loading library function:")) + wxT("\n\"") + wxT("GetFinalPathNameByHandleW") + wxT("\"")); const unsigned BUFFER_SIZE = 10000; TCHAR targetPath[BUFFER_SIZE]; - const DWORD rv = getDllHandler().getFinalPathNameByHandle( + const DWORD rv = KernelDllHandler::getInstance().getFinalPathNameByHandle( hDir, targetPath, BUFFER_SIZE, @@ -669,8 +665,8 @@ inline void setWin32FileInformation(const FILETIME& lastWriteTime, const DWORD fileSizeHigh, const DWORD fileSizeLow, FreeFileSync::FileInfo& output) { //convert UTC FILETIME to ANSI C format (number of seconds since Jan. 1st 1970 UTC) - wxLongLong writeTimeLong(lastWriteTime.dwHighDateTime, lastWriteTime.dwLowDateTime); - writeTimeLong /= 10000000; //reduce precision to 1 second (FILETIME has unit 10^-7 s) + wxLongLong writeTimeLong(wxInt32(lastWriteTime.dwHighDateTime), lastWriteTime.dwLowDateTime); + writeTimeLong /= 10000000; //reduce precision to 1 second (FILETIME has unit 10^-7 s) writeTimeLong -= wxLongLong(2, 3054539008UL); //timeshift between ansi C time and FILETIME in seconds == 11644473600s output.lastWriteTimeRaw = writeTimeLong; diff --git a/library/filter.cpp b/library/filter.cpp index d5255367..d9ba8c5f 100644 --- a/library/filter.cpp +++ b/library/filter.cpp @@ -5,6 +5,8 @@ #include <vector> #include "resources.h" +using FreeFileSync::FilterProcess; + void compoundStringToTable(const Zstring& compoundInput, const DefaultChar* delimiter, std::vector<Zstring>& output) { @@ -42,21 +44,6 @@ void mergeVectors(std::vector<Zstring>& changing, const std::vector<Zstring>& in } -inline -void formatFilterString(Zstring& filter) -{ -#ifdef FFS_WIN - //Windows does NOT distinguish between upper/lower-case - filter.MakeLower(); -#elif defined FFS_LINUX - //Linux DOES distinguish between upper/lower-case -//nothing to do here -#else - adapt; -#endif -} - - std::vector<Zstring> compoundStringToFilter(const Zstring& filterString) { //delimiters may be ';' or '\n' @@ -78,12 +65,26 @@ std::vector<Zstring> compoundStringToFilter(const Zstring& filterString) inline void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, std::set<Zstring>& directoryFilter) { - //Test if filtername ends with GlobalResources::FILE_NAME_SEPARATOR, ignoring '*' and '?'. - //If so, treat as filter for directory and add to directoryFilter. - if (!filtername.empty()) + Zstring filterFormatted = filtername; + +#ifdef FFS_WIN + //Windows does NOT distinguish between upper/lower-case + filterFormatted.MakeLower(); +#elif defined FFS_LINUX + //Linux DOES distinguish between upper/lower-case +//nothing to do here +#endif + + //remove leading separators (keep BEFORE test for Zstring::empty()!) + if (filterFormatted.length() > 0 && *filterFormatted.c_str() == GlobalResources::FILE_NAME_SEPARATOR) + filterFormatted = Zstring(filterFormatted.c_str() + 1); + + if (!filterFormatted.empty()) { - const DefaultChar* filter = filtername.c_str(); - int i = filtername.length() - 1; + //Test if filterFormatted ends with GlobalResources::FILE_NAME_SEPARATOR, ignoring '*' and '?'. + //If so, treat as filter for directory and add to directoryFilter. + const DefaultChar* filter = filterFormatted.c_str(); + int i = filterFormatted.length() - 1; while (filter[i] == DefaultChar('*') || filter[i] == DefaultChar('?')) { --i; @@ -94,37 +95,46 @@ void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, st if (i >= 0 && filter[i] == GlobalResources::FILE_NAME_SEPARATOR) //last FILE_NAME_SEPARATOR found { - if (i != int(filtername.length()) - 1) // "name\*" + if (i != int(filterFormatted.length()) - 1) // "name\*" { - fileFilter.insert(filtername); - directoryFilter.insert(filtername); + fileFilter.insert(filterFormatted); + directoryFilter.insert(filterFormatted); } - //else: "name\" -> not inserted directly + //else // "name\" if (i > 0) // "name\*" or "name\": add "name" to directory filter - directoryFilter.insert(Zstring(filtername.c_str(), i)); + directoryFilter.insert(Zstring(filterFormatted.c_str(), i)); } else { - fileFilter.insert(filtername); - directoryFilter.insert(filtername); + fileFilter.insert(filterFormatted); + directoryFilter.insert(filterFormatted); } } } inline -bool matchesFilter(const Zstring& name, const std::set<Zstring>& filter) +bool matchesFilter(const DefaultChar* name, const std::set<Zstring>& filter) { +#ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case + Zstring nameFormatted = name; + nameFormatted.MakeLower(); +#elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case + const DefaultChar* const nameFormatted = name; //nothing to do here +#endif + for (std::set<Zstring>::iterator j = filter.begin(); j != filter.end(); ++j) - if (name.Matches(*j)) + if (Zstring::Matches(nameFormatted, *j)) return true; return false; } +//############################################################## + -void FreeFileSync::filterGridData(FolderComparison& folderCmp, const wxString& includeFilter, const wxString& excludeFilter) +FilterProcess::FilterProcess(const wxString& includeFilter, const wxString& excludeFilter) { //no need for regular expressions! In tests wxRegex was by factor of 10 slower than wxString::Matches()!! @@ -133,26 +143,37 @@ void FreeFileSync::filterGridData(FolderComparison& folderCmp, const wxString& i std::vector<Zstring> includeList = compoundStringToFilter(includeFilter.c_str()); std::vector<Zstring> excludeList = compoundStringToFilter(excludeFilter.c_str()); -//############################################################## //setup include/exclude filters for files and directories - std::set<Zstring> filterFileIn; - std::set<Zstring> filterFolderIn; for (std::vector<Zstring>::iterator i = includeList.begin(); i != includeList.end(); ++i) - { - formatFilterString(*i); //format entry addFilterEntry(*i, filterFileIn, filterFolderIn); - } - std::set<Zstring> filterFileEx; - std::set<Zstring> filterFolderEx; for (std::vector<Zstring>::iterator i = excludeList.begin(); i != excludeList.end(); ++i) - { - formatFilterString(*i); //format entry addFilterEntry(*i, filterFileEx, filterFolderEx); - } +} + + +bool FilterProcess::matchesFileFilter(const DefaultChar* relFilename) const +{ + if ( matchesFilter(relFilename, filterFileIn) && //process include filters + !matchesFilter(relFilename, filterFileEx)) //process exclude filters + return true; + else + return false; +} + + +bool FilterProcess::matchesDirFilter(const DefaultChar* relDirname) const +{ + if ( matchesFilter(relDirname, filterFolderIn) && //process include filters + !matchesFilter(relDirname, filterFolderEx)) //process exclude filters + return true; + else + return false; +} -//############################################################## +void FilterProcess::filterGridData(FolderComparison& folderCmp) const +{ //execute filtering... for (FolderComparison::iterator j = folderCmp.begin(); j != folderCmp.end(); ++j) { @@ -160,18 +181,10 @@ void FreeFileSync::filterGridData(FolderComparison& folderCmp, const wxString& i for (FileComparison::iterator i = fileCmp.begin(); i != fileCmp.end(); ++i) { - Zstring filenameLeft = i->fileDescrLeft.fullName; - Zstring filenameRight = i->fileDescrRight.fullName; - - formatFilterString(filenameLeft); - formatFilterString(filenameRight); - - //left hand side if (i->fileDescrLeft.objType == FileDescrLine::TYPE_FILE) { - if ( !matchesFilter(filenameLeft, filterFileIn) || //process include filters - matchesFilter(filenameLeft, filterFileEx)) //process exclude filters + if (!matchesFileFilter(i->fileDescrLeft.relativeName.c_str())) { i->selectedForSynchronization = false; continue; @@ -179,19 +192,16 @@ void FreeFileSync::filterGridData(FolderComparison& folderCmp, const wxString& i } else if (i->fileDescrLeft.objType == FileDescrLine::TYPE_DIRECTORY) { - if ( !matchesFilter(filenameLeft, filterFolderIn) || //process include filters - matchesFilter(filenameLeft, filterFolderEx)) //process exclude filters + if (!matchesDirFilter(i->fileDescrLeft.relativeName.c_str())) { i->selectedForSynchronization = false; continue; } } - //right hand side - if (i->fileDescrRight.objType == FileDescrLine::TYPE_FILE) + else if (i->fileDescrRight.objType == FileDescrLine::TYPE_FILE) { - if ( !matchesFilter(filenameRight, filterFileIn) || //process include filters - matchesFilter(filenameRight, filterFileEx)) //process exclude filters + if (!matchesFileFilter(i->fileDescrRight.relativeName.c_str())) { i->selectedForSynchronization = false; continue; @@ -199,8 +209,7 @@ void FreeFileSync::filterGridData(FolderComparison& folderCmp, const wxString& i } else if (i->fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY) { - if ( !matchesFilter(filenameRight, filterFolderIn) || //process include filters - matchesFilter(filenameRight, filterFolderEx)) //process exclude filters + if (!matchesDirFilter(i->fileDescrRight.relativeName.c_str())) { i->selectedForSynchronization = false; continue; @@ -227,14 +236,14 @@ void inOrExcludeAllRows(FreeFileSync::FolderComparison& folderCmp) } -void FreeFileSync::includeAllRowsOnGrid(FolderComparison& folderCmp) +void FilterProcess::includeAllRowsOnGrid(FolderComparison& folderCmp) { //remove all filters on currentGridData inOrExcludeAllRows<true>(folderCmp); } -void FreeFileSync::excludeAllRowsOnGrid(FolderComparison& folderCmp) +void FilterProcess::excludeAllRowsOnGrid(FolderComparison& folderCmp) { //exclude all rows on currentGridData inOrExcludeAllRows<false>(folderCmp); diff --git a/library/filter.h b/library/filter.h index 3d0598e1..dd716680 100644 --- a/library/filter.h +++ b/library/filter.h @@ -6,9 +6,25 @@ namespace FreeFileSync { - void filterGridData(FolderComparison& folderCmp, const wxString& includeFilter, const wxString& excludeFilter); - void includeAllRowsOnGrid(FolderComparison& folderCmp); - void excludeAllRowsOnGrid(FolderComparison& folderCmp); + class FilterProcess //relative filtering + { + public: + FilterProcess(const wxString& includeFilter, const wxString& excludeFilter); + + bool matchesFileFilter(const DefaultChar* relFilename) const; + bool matchesDirFilter(const DefaultChar* relDirname) const; + + void filterGridData(FolderComparison& folderCmp) const; + + static void includeAllRowsOnGrid(FolderComparison& folderCmp); + static void excludeAllRowsOnGrid(FolderComparison& folderCmp); + + private: + std::set<Zstring> filterFileIn; + std::set<Zstring> filterFolderIn; + std::set<Zstring> filterFileEx; + std::set<Zstring> filterFolderEx; + }; } diff --git a/library/localization.cpp b/library/localization.cpp index 328f37be..ef433012 100644 --- a/library/localization.cpp +++ b/library/localization.cpp @@ -129,7 +129,7 @@ void CustomLocale::setLanguage(const int language) currentLanguage = wxLANGUAGE_ENGLISH; } - static bool initialized = false; //wxLocale is a global too! + static bool initialized = false; //wxLocale is a static global too! if (!initialized) { initialized = true; @@ -152,7 +152,7 @@ void CustomLocale::setLanguage(const int language) //Linux: 0xa \n //Mac: 0xd \r //Win: 0xd 0xa \r\n <- language files are in Windows format - for (int rowNumber = 0; langFile.getline(temp, bufferSize, 0xd); ++rowNumber) //specify delimiter explicitly + for (int rowNumber = 0; langFile.getline(temp, bufferSize, 0xD); ++rowNumber) //specify delimiter explicitly { langFile.get(); //discard the 0xa character @@ -165,8 +165,11 @@ void CustomLocale::setLanguage(const int language) currentLine.original = formattedString; else { - currentLine.translation = formattedString; - translationDB->insert(currentLine); + if (!formattedString.empty()) + { + currentLine.translation = formattedString; + translationDB->insert(currentLine); + } } } langFile.close(); diff --git a/library/processXml.cpp b/library/processXml.cpp index c16b9d76..750bd879 100644 --- a/library/processXml.cpp +++ b/library/processXml.cpp @@ -19,12 +19,12 @@ const wxString xmlAccess::GLOBAL_CONFIG_FILE = wxT("GlobalSettings.xml"); bool readXmlElementValue(std::string& output, const TiXmlElement* parent, const std::string& name); bool readXmlElementValue(int& output, const TiXmlElement* parent, const std::string& name); bool readXmlElementValue(CompareVariant& output, const TiXmlElement* parent, const std::string& name); -bool readXmlElementValue(SyncConfiguration::Direction& output, const TiXmlElement* parent, const std::string& name); +bool readXmlElementValue(SyncDirection& output, const TiXmlElement* parent, const std::string& name); bool readXmlElementValue(bool& output, const TiXmlElement* parent, const std::string& name); void addXmlElement(TiXmlElement* parent, const std::string& name, const std::string& value); void addXmlElement(TiXmlElement* parent, const std::string& name, const int value); -void addXmlElement(TiXmlElement* parent, const std::string& name, const SyncConfiguration::Direction value); +void addXmlElement(TiXmlElement* parent, const std::string& name, const SyncDirection value); void addXmlElement(TiXmlElement* parent, const std::string& name, const bool value); @@ -306,17 +306,17 @@ bool readXmlElementValue(CompareVariant& output, const TiXmlElement* parent, con } -bool readXmlElementValue(SyncConfiguration::Direction& output, const TiXmlElement* parent, const std::string& name) +bool readXmlElementValue(SyncDirection& output, const TiXmlElement* parent, const std::string& name) { std::string dummy; if (readXmlElementValue(dummy, parent, name)) { if (dummy == "left") - output = SyncConfiguration::SYNC_DIR_LEFT; + output = SYNC_DIR_LEFT; else if (dummy == "right") - output = SyncConfiguration::SYNC_DIR_RIGHT; + output = SYNC_DIR_RIGHT; else //treat all other input as "none" - output = SyncConfiguration::SYNC_DIR_NONE; + output = SYNC_DIR_NONE; return true; } @@ -460,8 +460,8 @@ bool XmlConfigInput::readXmlGuiConfig(xmlAccess::XmlGuiConfig& outputCfg) if (guiConfig) { readXmlElementValue(outputCfg.hideFilteredElements, guiConfig, "HideFiltered"); - readXmlElementValue(outputCfg.ignoreErrors, guiConfig, "IgnoreErrors"); + readXmlElementValue(outputCfg.syncPreviewEnabled, guiConfig, "SyncPreviewActive"); } return true; @@ -508,7 +508,7 @@ bool XmlConfigInput::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputC TiXmlElement* global = hRoot.FirstChild("Shared").ToElement(); if (global) { - //program language + //try to read program language setting readXmlElementValue(outputCfg.shared.programLanguage, global, "Language"); //max. allowed file time deviation @@ -516,6 +516,9 @@ bool XmlConfigInput::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputC if (readXmlElementValue(dummy, global, "FileTimeTolerance")) outputCfg.shared.fileTimeTolerance = dummy; + //ignore +/- 1 hour due to DST change + readXmlElementValue(outputCfg.shared.ignoreOneHourDiff, global, "IgnoreOneHourDifference"); + //traverse into symbolic links (to folders) readXmlElementValue(outputCfg.shared.traverseDirectorySymlinks, global, "TraverseDirectorySymlinks"); @@ -537,6 +540,12 @@ bool XmlConfigInput::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputC //check free disk space readXmlElementValue(outputCfg.shared.warningNotEnoughDiskSpace, warnings, "CheckForFreeDiskSpace"); + + //check for unresolved conflicts + readXmlElementValue(outputCfg.shared.warningUnresolvedConflicts, warnings, "CheckForUnresolvedConflicts"); + + //small reminder that synchronization will be starting immediately + readXmlElementValue(outputCfg.shared.warningSynchronizationStarting, warnings, "SynchronizationStarting"); } //gui specific global settings (optional) @@ -558,19 +567,19 @@ bool XmlConfigInput::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputC //########################################################### //read column attributes TiXmlElement* leftColumn = TiXmlHandle(mainWindow).FirstChild("LeftColumns").FirstChild("Column").ToElement(); - unsigned int colType = 0; + unsigned int colPos = 0; while (leftColumn) { - const char* visible = leftColumn->Attribute("Visible"); - const char* position = leftColumn->Attribute("Position"); - const char* width = leftColumn->Attribute("Width"); + const char* type = leftColumn->Attribute("Type"); + const char* visible = leftColumn->Attribute("Visible"); + const char* width = leftColumn->Attribute("Width"); - if (visible && position && width) //may be NULL!! + if (type && visible && width) //may be NULL!! { xmlAccess::ColumnAttrib newAttrib; - newAttrib.type = xmlAccess::ColumnTypes(colType); + newAttrib.type = xmlAccess::ColumnTypes(globalFunctions::stringToInt(type)); newAttrib.visible = std::string(visible) != std::string("false"); - newAttrib.position = globalFunctions::stringToInt(position); + newAttrib.position = colPos; newAttrib.width = globalFunctions::stringToInt(width); outputCfg.gui.columnAttribLeft.push_back(newAttrib); } @@ -578,23 +587,23 @@ bool XmlConfigInput::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputC break; leftColumn = leftColumn->NextSiblingElement(); - ++colType; + ++colPos; } TiXmlElement* rightColumn = TiXmlHandle(mainWindow).FirstChild("RightColumns").FirstChild("Column").ToElement(); - colType = 0; + colPos = 0; while (rightColumn) { - const char* visible = rightColumn->Attribute("Visible"); - const char* position = rightColumn->Attribute("Position"); - const char* width = rightColumn->Attribute("Width"); + const char* type = rightColumn->Attribute("Type"); + const char* visible = rightColumn->Attribute("Visible"); + const char* width = rightColumn->Attribute("Width"); - if (visible && position && width) //may be NULL!! + if (type && visible && width) //may be NULL!! { xmlAccess::ColumnAttrib newAttrib; - newAttrib.type = xmlAccess::ColumnTypes(colType); + newAttrib.type = xmlAccess::ColumnTypes(globalFunctions::stringToInt(type)); newAttrib.visible = std::string(visible) != std::string("false"); - newAttrib.position = globalFunctions::stringToInt(position); + newAttrib.position = colPos; newAttrib.width = globalFunctions::stringToInt(width); outputCfg.gui.columnAttribRight.push_back(newAttrib); } @@ -602,7 +611,7 @@ bool XmlConfigInput::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputC break; rightColumn = rightColumn->NextSiblingElement(); - ++colType; + ++colPos; } //load folder history elements @@ -722,13 +731,13 @@ void addXmlElement(TiXmlElement* parent, const std::string& name, const long val } -void addXmlElement(TiXmlElement* parent, const std::string& name, const SyncConfiguration::Direction value) +void addXmlElement(TiXmlElement* parent, const std::string& name, const SyncDirection value) { - if (value == SyncConfiguration::SYNC_DIR_LEFT) + if (value == SYNC_DIR_LEFT) addXmlElement(parent, name, std::string("left")); - else if (value == SyncConfiguration::SYNC_DIR_RIGHT) + else if (value == SYNC_DIR_RIGHT) addXmlElement(parent, name, std::string("right")); - else if (value == SyncConfiguration::SYNC_DIR_NONE) + else if (value == SYNC_DIR_NONE) addXmlElement(parent, name, std::string("none")); else assert(false); @@ -841,8 +850,8 @@ bool XmlConfigOutput::writeXmlGuiConfig(const xmlAccess::XmlGuiConfig& inputCfg) root->LinkEndChild(guiConfig); addXmlElement(guiConfig, "HideFiltered", inputCfg.hideFilteredElements); - addXmlElement(guiConfig, "IgnoreErrors", inputCfg.ignoreErrors); + addXmlElement(guiConfig, "SyncPreviewActive", inputCfg.syncPreviewEnabled); return true; } @@ -885,6 +894,9 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& //max. allowed file time deviation addXmlElement(global, "FileTimeTolerance", int(inputCfg.shared.fileTimeTolerance)); + //ignore +/- 1 hour due to DST change + addXmlElement(global, "IgnoreOneHourDifference", inputCfg.shared.ignoreOneHourDiff); + //traverse into symbolic links (to folders) addXmlElement(global, "TraverseDirectorySymlinks", inputCfg.shared.traverseDirectorySymlinks); @@ -907,6 +919,12 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& //check free disk space addXmlElement(warnings, "CheckForFreeDiskSpace", inputCfg.shared.warningNotEnoughDiskSpace); + //check for unresolved conflicts + addXmlElement(warnings, "CheckForUnresolvedConflicts", inputCfg.shared.warningUnresolvedConflicts); + + //small reminder that synchronization will be starting immediately + addXmlElement(warnings, "SynchronizationStarting", inputCfg.shared.warningSynchronizationStarting); + //################################################################### //write global gui settings @@ -937,32 +955,32 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& TiXmlElement* leftColumn = new TiXmlElement("LeftColumns"); mainWindow->LinkEndChild(leftColumn); xmlAccess::ColumnAttributes columnAtrribLeftCopy = inputCfg.gui.columnAttribLeft; //can't change const vector - sort(columnAtrribLeftCopy.begin(), columnAtrribLeftCopy.end(), xmlAccess::sortByType); + sort(columnAtrribLeftCopy.begin(), columnAtrribLeftCopy.end(), xmlAccess::sortByPositionOnly); for (unsigned int i = 0; i < columnAtrribLeftCopy.size(); ++i) { TiXmlElement* subElement = new TiXmlElement("Column"); leftColumn->LinkEndChild(subElement); const xmlAccess::ColumnAttrib& colAttrib = columnAtrribLeftCopy[i]; + subElement->SetAttribute("Type", colAttrib.type); if (colAttrib.visible) subElement->SetAttribute("Visible", "true"); else subElement->SetAttribute("Visible", "false"); - subElement->SetAttribute("Position", colAttrib.position); subElement->SetAttribute("Width", colAttrib.width); } TiXmlElement* rightColumn = new TiXmlElement("RightColumns"); mainWindow->LinkEndChild(rightColumn); xmlAccess::ColumnAttributes columnAtrribRightCopy = inputCfg.gui.columnAttribRight; - sort(columnAtrribRightCopy.begin(), columnAtrribRightCopy.end(), xmlAccess::sortByType); + sort(columnAtrribRightCopy.begin(), columnAtrribRightCopy.end(), xmlAccess::sortByPositionOnly); for (unsigned int i = 0; i < columnAtrribRightCopy.size(); ++i) { TiXmlElement* subElement = new TiXmlElement("Column"); rightColumn->LinkEndChild(subElement); const xmlAccess::ColumnAttrib& colAttrib = columnAtrribRightCopy[i]; + subElement->SetAttribute("Type", colAttrib.type); if (colAttrib.visible) subElement->SetAttribute("Visible", "true"); else subElement->SetAttribute("Visible", "false"); - subElement->SetAttribute("Position", colAttrib.position); subElement->SetAttribute("Width", colAttrib.width); } @@ -1094,7 +1112,9 @@ bool xmlAccess::supportForSymbolicLinks() void xmlAccess::XmlGlobalSettings::_Shared::resetWarnings() { - warningDependentFolders = true; - warningSignificantDifference = true; - warningNotEnoughDiskSpace = true; + warningDependentFolders = true; + warningSignificantDifference = true; + warningNotEnoughDiskSpace = true; + warningUnresolvedConflicts = true; + warningSynchronizationStarting = true; } diff --git a/library/processXml.h b/library/processXml.h index 763edbca..313fbfae 100644 --- a/library/processXml.h +++ b/library/processXml.h @@ -26,21 +26,21 @@ namespace xmlAccess enum ColumnTypes { - FILENAME = 0, + DIRECTORY, + FULL_PATH, REL_PATH, + FILENAME, SIZE, - DATE, - FULL_NAME, - DIRECTORY + DATE }; const unsigned COLUMN_TYPE_COUNT = 6; struct ColumnAttrib { ColumnTypes type; - bool visible; - unsigned position; - int width; + bool visible; + unsigned int position; + int width; }; typedef std::vector<ColumnAttrib> ColumnAttributes; @@ -51,20 +51,23 @@ namespace xmlAccess { XmlGuiConfig() : hideFilteredElements(false), - ignoreErrors(false) {} //initialize values + ignoreErrors(false), + syncPreviewEnabled(true) {} //initialize values FreeFileSync::MainConfiguration mainCfg; std::vector<FreeFileSync::FolderPair> directoryPairs; bool hideFilteredElements; bool ignoreErrors; //reaction on error situation during synchronization + bool syncPreviewEnabled; bool operator==(const XmlGuiConfig& other) const { - return mainCfg == other.mainCfg && - directoryPairs == other.directoryPairs && + return mainCfg == other.mainCfg && + directoryPairs == other.directoryPairs && hideFilteredElements == other.hideFilteredElements && - ignoreErrors == other.ignoreErrors; + ignoreErrors == other.ignoreErrors && + syncPreviewEnabled == other.syncPreviewEnabled; } bool operator!=(const XmlGuiConfig& other) const @@ -98,6 +101,7 @@ namespace xmlAccess _Shared() : programLanguage(retrieveSystemLanguage()), fileTimeTolerance(2), //default 2s: FAT vs NTFS + ignoreOneHourDiff(true), traverseDirectorySymlinks(false), copyFileSymlinks(supportForSymbolicLinks()), lastUpdateCheck(0) @@ -106,7 +110,8 @@ namespace xmlAccess } int programLanguage; - unsigned fileTimeTolerance; //max. allowed file time deviation + unsigned int fileTimeTolerance; //max. allowed file time deviation + bool ignoreOneHourDiff; //ignore +/- 1 hour due to DST change bool traverseDirectorySymlinks; bool copyFileSymlinks; //copy symbolic link instead of target file long lastUpdateCheck; //time of last update check @@ -117,6 +122,8 @@ namespace xmlAccess bool warningDependentFolders; bool warningSignificantDifference; bool warningNotEnoughDiskSpace; + bool warningUnresolvedConflicts; + bool warningSynchronizationStarting; } shared; //--------------------------------------------------------------------- diff --git a/library/resources.cpp b/library/resources.cpp index 23d1ac37..9e43a78a 100644 --- a/library/resources.cpp +++ b/library/resources.cpp @@ -37,29 +37,32 @@ GlobalResources::GlobalResources() bitmapResource[wxT("about_small.png")] = (bitmapAboutSmall = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("website.png")] = (bitmapWebsite = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("exit.png")] = (bitmapExit = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("sync.png")] = (bitmapSync = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("compare.png")] = (bitmapCompare = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("compare disabled.png")] = (bitmapCompareDisabled = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("sync.png")] = (bitmapSync = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("sync disabled.png")] = (bitmapSyncDisabled = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("swap.png")] = (bitmapSwap = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("help.png")] = (bitmapHelp = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("equal.png")] = (bitmapEqual = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("equalAct.png")] = (bitmapEqualAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("equalDeact.png")] = (bitmapEqualDeact = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("leftOnly.png")] = (bitmapLeftOnly = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("leftOnlyAct.png")] = (bitmapLeftOnlyAct = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("leftOnlyDeact.png")] = (bitmapLeftOnlyDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("rightOnly.png")] = (bitmapRightOnly = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("rightOnlyAct.png")] = (bitmapRightOnlyAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("rightOnlyDeact.png")] = (bitmapRightOnlyDeact = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("leftNewer.png")] = (bitmapLeftNewer = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("leftNewerAct.png")] = (bitmapLeftNewerAct = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("leftNewerDeact.png")] = (bitmapLeftNewerDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("different.png")] = (bitmapDifferent = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("differentAct.png")] = (bitmapDifferentAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("differentDeact.png")] = (bitmapDifferentDeact = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("rightNewer.png")] = (bitmapRightNewer = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("rightNewerAct.png")] = (bitmapRightNewerAct = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("rightNewerDeact.png")] = (bitmapRightNewerDeact = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("rightOnly.png")] = (bitmapRightOnly = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("rightOnlyAct.png")] = (bitmapRightOnlyAct = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("rightOnlyDeact.png")] = (bitmapRightOnlyDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("different.png")] = (bitmapDifferent = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("differentAct.png")] = (bitmapDifferentAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("differentDeact.png")] = (bitmapDifferentDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("equal.png")] = (bitmapEqual = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("equalAct.png")] = (bitmapEqualAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("equalDeact.png")] = (bitmapEqualDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("conflictAct.png")] = (bitmapConflictAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("conflictDeact.png")] = (bitmapConflictDeact = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("include.png")] = (bitmapInclude = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("exclude.png")] = (bitmapExclude = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("filter active.png")] = (bitmapFilterOn = new wxBitmap(wxNullBitmap)); @@ -80,7 +83,7 @@ GlobalResources::GlobalResources() bitmapResource[wxT("statusSuccess.png")] = (bitmapStatusSuccess = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("statusWarning.png")] = (bitmapStatusWarning = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("statusScanning.png")] = (bitmapStatusScanning = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("statusComparing.png")] = (bitmapStatusComparing = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("statusBinaryCompare.png")]= (bitmapStatusBinCompare = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("statusSyncing.png")] = (bitmapStatusSyncing = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("logo.png")] = (bitmapLogo = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("statusEdge.png")] = (bitmapStatusEdge = new wxBitmap(wxNullBitmap)); @@ -104,6 +107,9 @@ GlobalResources::GlobalResources() bitmapResource[wxT("settings_small.png")] = (bitmapSettingsSmall = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("recycler.png")] = (bitmapRecycler = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("shift.png")] = (bitmapShift = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncConfig.png")] = (bitmapSyncCfg = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncPreview.png")] = (bitmapPreview = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncPreviewDisabl.png")] = (bitmapPreviewDisabled = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("question.png")] = (bitmapQuestion = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("china.png")] = (bitmapChina = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("holland.png")] = (bitmapHolland = new wxBitmap(wxNullBitmap)); @@ -118,6 +124,30 @@ GlobalResources::GlobalResources() bitmapResource[wxT("brazil.png")] = (bitmapBrazil = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("slovakia.png")] = (bitmapSlovakia = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("spain.png")] = (bitmapSpain = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirLeftAct.png")] = (bitmapSyncDirLeftAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirLeftDeact.png")] = (bitmapSyncDirLeftDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirRightAct.png")] = (bitmapSyncDirRightAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirRightDeact.png")] = (bitmapSyncDirRightDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirNoneAct.png")] = (bitmapSyncDirNoneAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirNoneDeact.png")] = (bitmapSyncDirNoneDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirLeftSmall.png")] = (bitmapSyncDirLeftSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirRightSmall.png")] = (bitmapSyncDirRightSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDirNoneSmall.png")] = (bitmapSyncDirNoneSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("leftOnlySmall.png")] = (bitmapLeftOnlySmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("rightOnlySmall.png")] = (bitmapRightOnlySmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("leftNewerSmall.png")] = (bitmapLeftNewerSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("rightNewerSmall.png")] = (bitmapRightNewerSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("equalSmall.png")] = (bitmapEqualSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("differentSmall.png")] = (bitmapDifferentSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("conflictSmall.png")] = (bitmapConflictSmall = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("create.png")] = (bitmapCreate = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("update.png")] = (bitmapUpdate = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("delete.png")] = (bitmapDelete = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("data.png")] = (bitmapData = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("cmpView.png")] = (bitmapCmpView = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncView.png")] = (bitmapSyncView = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("toggleViewSmall.png")] = (bitmapSwitchViewSmall = new wxBitmap(wxNullBitmap)); + //init all the other resource files animationMoney = new wxAnimation(wxNullAnimation); diff --git a/library/resources.h b/library/resources.h index 5de79ec2..60b4ab48 100644 --- a/library/resources.h +++ b/library/resources.h @@ -36,29 +36,32 @@ public: wxBitmap* bitmapAboutSmall; wxBitmap* bitmapWebsite; wxBitmap* bitmapExit; - wxBitmap* bitmapSync; wxBitmap* bitmapCompare; + wxBitmap* bitmapCompareDisabled; + wxBitmap* bitmapSync; wxBitmap* bitmapSyncDisabled; wxBitmap* bitmapSwap; wxBitmap* bitmapHelp; - wxBitmap* bitmapEqual; - wxBitmap* bitmapEqualAct; - wxBitmap* bitmapEqualDeact; wxBitmap* bitmapLeftOnly; wxBitmap* bitmapLeftOnlyAct; wxBitmap* bitmapLeftOnlyDeact; + wxBitmap* bitmapRightOnly; + wxBitmap* bitmapRightOnlyAct; + wxBitmap* bitmapRightOnlyDeact; wxBitmap* bitmapLeftNewer; wxBitmap* bitmapLeftNewerAct; wxBitmap* bitmapLeftNewerDeact; - wxBitmap* bitmapDifferent; - wxBitmap* bitmapDifferentAct; - wxBitmap* bitmapDifferentDeact; wxBitmap* bitmapRightNewer; wxBitmap* bitmapRightNewerAct; wxBitmap* bitmapRightNewerDeact; - wxBitmap* bitmapRightOnly; - wxBitmap* bitmapRightOnlyAct; - wxBitmap* bitmapRightOnlyDeact; + wxBitmap* bitmapEqual; + wxBitmap* bitmapEqualAct; + wxBitmap* bitmapEqualDeact; + wxBitmap* bitmapDifferent; + wxBitmap* bitmapDifferentAct; + wxBitmap* bitmapDifferentDeact; + wxBitmap* bitmapConflictAct; + wxBitmap* bitmapConflictDeact; wxBitmap* bitmapInclude; wxBitmap* bitmapExclude; wxBitmap* bitmapFilterOn; @@ -79,7 +82,7 @@ public: wxBitmap* bitmapStatusSuccess; wxBitmap* bitmapStatusWarning; wxBitmap* bitmapStatusScanning; - wxBitmap* bitmapStatusComparing; + wxBitmap* bitmapStatusBinCompare; wxBitmap* bitmapStatusSyncing; wxBitmap* bitmapLogo; wxBitmap* bitmapStatusEdge; @@ -103,6 +106,9 @@ public: wxBitmap* bitmapSettingsSmall; wxBitmap* bitmapRecycler; wxBitmap* bitmapShift; + wxBitmap* bitmapSyncCfg; + wxBitmap* bitmapPreview; + wxBitmap* bitmapPreviewDisabled; wxBitmap* bitmapQuestion; wxBitmap* bitmapChina; wxBitmap* bitmapHolland; @@ -117,6 +123,29 @@ public: wxBitmap* bitmapBrazil; wxBitmap* bitmapSlovakia; wxBitmap* bitmapSpain; + wxBitmap* bitmapSyncDirLeftAct; + wxBitmap* bitmapSyncDirLeftDeact; + wxBitmap* bitmapSyncDirRightAct; + wxBitmap* bitmapSyncDirRightDeact; + wxBitmap* bitmapSyncDirNoneAct; + wxBitmap* bitmapSyncDirNoneDeact; + wxBitmap* bitmapSyncDirLeftSmall; + wxBitmap* bitmapSyncDirRightSmall; + wxBitmap* bitmapSyncDirNoneSmall; + wxBitmap* bitmapLeftOnlySmall; + wxBitmap* bitmapRightOnlySmall; + wxBitmap* bitmapLeftNewerSmall; + wxBitmap* bitmapRightNewerSmall; + wxBitmap* bitmapEqualSmall; + wxBitmap* bitmapDifferentSmall; + wxBitmap* bitmapConflictSmall; + wxBitmap* bitmapCreate; + wxBitmap* bitmapUpdate; + wxBitmap* bitmapDelete; + wxBitmap* bitmapData; + wxBitmap* bitmapCmpView; + wxBitmap* bitmapSyncView; + wxBitmap* bitmapSwitchViewSmall; wxAnimation* animationMoney; wxAnimation* animationSync; diff --git a/library/statusHandler.cpp b/library/statusHandler.cpp index e19c9904..78dba057 100644 --- a/library/statusHandler.cpp +++ b/library/statusHandler.cpp @@ -16,8 +16,7 @@ void updateUiNow() bool updateUiIsAllowed() { static wxLongLong lastExec = 0; - - wxLongLong newExec = wxGetLocalTimeMillis(); + const wxLongLong newExec = wxGetLocalTimeMillis(); if (newExec - lastExec >= UI_UPDATE_INTERVAL) //perform ui updates not more often than necessary { diff --git a/library/statusHandler.h b/library/statusHandler.h index 18d9f129..fe64f3cd 100644 --- a/library/statusHandler.h +++ b/library/statusHandler.h @@ -54,7 +54,7 @@ public: virtual void forceUiRefresh() = 0; void requestUiRefresh(bool allowAbort = true); //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh() - void requestAbortion(); //does NOT call abortThisProcess immediately, but when appropriate (e.g. async. processes finished) + void requestAbortion(); //this does NOT call abortThisProcess immediately, but when appropriate (e.g. async. processes finished) bool abortIsRequested(); @@ -63,7 +63,7 @@ public: virtual void reportFatalError(const Zstring& errorMessage) = 0; //non-recoverable error situation, implement abort! virtual void reportWarning(const Zstring& warningMessage, bool& dontShowAgain) = 0; -protected: +private: virtual void abortThisProcess() = 0; bool abortRequested; diff --git a/library/zstring.cpp b/library/zstring.cpp index abded9d0..ddf1fc73 100644 --- a/library/zstring.cpp +++ b/library/zstring.cpp @@ -1,5 +1,4 @@ #include "zstring.h" -#include <wx/intl.h> #include "globalFunctions.h" #ifdef FFS_WIN @@ -124,6 +123,12 @@ bool Zstring::Matches(const DefaultChar* mask) const } +bool Zstring::Matches(const DefaultChar* name, const DefaultChar* mask) +{ + return matchesHelper(name, mask); +} + + Zstring& Zstring::Trim(bool fromRight) { const size_t thisLen = length(); diff --git a/library/zstring.h b/library/zstring.h index 2b6bc475..007922d8 100644 --- a/library/zstring.h +++ b/library/zstring.h @@ -66,6 +66,7 @@ public: Zstring BeforeLast(DefaultChar ch) const; size_t Find(DefaultChar ch, bool fromEnd) const; bool Matches(const DefaultChar* mask) const; + static bool Matches(const DefaultChar* name, const DefaultChar* mask); Zstring& Trim(bool fromRight); //from right or left Zstring& MakeLower(); diff --git a/structures.h b/structures.h index 9fe6c823..00efb624 100644 --- a/structures.h +++ b/structures.h @@ -17,34 +17,36 @@ namespace FreeFileSync }; + enum SyncDirection + { + SYNC_DIR_LEFT, + SYNC_DIR_RIGHT, + SYNC_DIR_NONE, + SYNC_UNRESOLVED_CONFLICT + }; + + struct SyncConfiguration { SyncConfiguration() : exLeftSideOnly(SYNC_DIR_RIGHT), - exRightSideOnly(SYNC_DIR_RIGHT), + exRightSideOnly(SYNC_DIR_LEFT), leftNewer(SYNC_DIR_RIGHT), - rightNewer(SYNC_DIR_RIGHT), - different(SYNC_DIR_RIGHT) {} - - enum Direction - { - SYNC_DIR_LEFT, - SYNC_DIR_RIGHT, - SYNC_DIR_NONE - }; + rightNewer(SYNC_DIR_LEFT), + different(SYNC_DIR_NONE) {} - Direction exLeftSideOnly; - Direction exRightSideOnly; - Direction leftNewer; - Direction rightNewer; - Direction different; + SyncDirection exLeftSideOnly; + SyncDirection exRightSideOnly; + SyncDirection leftNewer; + SyncDirection rightNewer; + SyncDirection different; bool operator==(const SyncConfiguration& other) const { - return exLeftSideOnly == other.exLeftSideOnly && + return exLeftSideOnly == other.exLeftSideOnly && exRightSideOnly == other.exRightSideOnly && - leftNewer == other.leftNewer && - rightNewer == other.rightNewer && + leftNewer == other.leftNewer && + rightNewer == other.rightNewer && different == other.different; } }; @@ -143,18 +145,24 @@ namespace FreeFileSync FILE_DIFFERENT, FILE_EQUAL, - FILE_UNDEFINED + FILE_CONFLICT, }; struct FileCompareLine { - FileCompareLine() : selectedForSynchronization(true) {} + FileCompareLine(const CompareFilesResult defaultCmpResult, + const SyncDirection defaultDirection, + const bool selected) : + cmpResult(defaultCmpResult), + direction(defaultDirection), + selectedForSynchronization(selected) {} FileDescrLine fileDescrLeft; FileDescrLine fileDescrRight; - CompareFilesResult cmpResult; + CompareFilesResult cmpResult; + SyncDirection direction; bool selectedForSynchronization; }; typedef std::vector<FileCompareLine> FileComparison; @@ -164,6 +172,12 @@ namespace FreeFileSync { FolderPair syncPair; //directories to be synced (ending with separator) FileComparison fileCmp; + + void swap(FolderCompareLine& other) + { + std::swap(syncPair, other.syncPair); + fileCmp.swap(other.fileCmp); + } }; typedef std::vector<FolderCompareLine> FolderComparison; diff --git a/synchronization.cpp b/synchronization.cpp index b8f2d6a6..43bf22a6 100644 --- a/synchronization.cpp +++ b/synchronization.cpp @@ -17,48 +17,18 @@ using namespace FreeFileSync; inline -SyncConfiguration::Direction getSyncDirection(const CompareFilesResult cmpResult, const SyncConfiguration& config) -{ - switch (cmpResult) - { - case FILE_LEFT_SIDE_ONLY: - return config.exLeftSideOnly; - break; - - case FILE_RIGHT_SIDE_ONLY: - return config.exRightSideOnly; - break; - - case FILE_RIGHT_NEWER: - return config.rightNewer; - break; - - case FILE_LEFT_NEWER: - return config.leftNewer; - break; - - case FILE_DIFFERENT: - return config.different; - break; - - default: - return SyncConfiguration::SYNC_DIR_NONE; - } -} - - -inline bool getBytesToTransfer(const FileCompareLine& fileCmpLine, - const SyncConfiguration& config, int& objectsToCreate, int& objectsToOverwrite, int& objectsToDelete, + int& conflicts, wxULongLong& dataToProcess) { //return false if nothing has to be done objectsToCreate = 0; //always initialize variables objectsToOverwrite = 0; objectsToDelete = 0; + conflicts = 0; dataToProcess = 0; //do not add filtered entries @@ -70,93 +40,101 @@ bool getBytesToTransfer(const FileCompareLine& fileCmpLine, { case FILE_LEFT_SIDE_ONLY: //get data to process - switch (getSyncDirection(fileCmpLine.cmpResult, config)) + switch (fileCmpLine.direction) { - case SyncConfiguration::SYNC_DIR_LEFT: //delete file on left + case SYNC_DIR_LEFT: //delete file on left dataToProcess = 0; objectsToDelete = 1; - break; - case SyncConfiguration::SYNC_DIR_RIGHT: //copy from left to right + return true; + case SYNC_DIR_RIGHT: //copy from left to right dataToProcess = fileCmpLine.fileDescrLeft.fileSize; objectsToCreate = 1; - break; - case SyncConfiguration::SYNC_DIR_NONE: + return true; + case SYNC_UNRESOLVED_CONFLICT: + assert(false); //conflicts have files on both sides + conflicts = 1; + return true; + case SYNC_DIR_NONE: return false; } - break; case FILE_RIGHT_SIDE_ONLY: - switch (getSyncDirection(fileCmpLine.cmpResult, config)) + switch (fileCmpLine.direction) { - case SyncConfiguration::SYNC_DIR_LEFT: //copy from right to left + case SYNC_DIR_LEFT: //copy from right to left dataToProcess = fileCmpLine.fileDescrRight.fileSize; objectsToCreate = 1; - break; - case SyncConfiguration::SYNC_DIR_RIGHT: //delete file on right + return true; + case SYNC_DIR_RIGHT: //delete file on right dataToProcess = 0; objectsToDelete = 1; - break; - case SyncConfiguration::SYNC_DIR_NONE: + return true; + case SYNC_UNRESOLVED_CONFLICT: + assert(false); //conflicts have files on both sides + conflicts = 1; + return true; + case SYNC_DIR_NONE: return false; } - break; case FILE_LEFT_NEWER: case FILE_RIGHT_NEWER: case FILE_DIFFERENT: + case FILE_CONFLICT: //get data to process - switch (getSyncDirection(fileCmpLine.cmpResult, config)) + switch (fileCmpLine.direction) { - case SyncConfiguration::SYNC_DIR_LEFT: //copy from right to left + case SYNC_DIR_LEFT: //copy from right to left dataToProcess = fileCmpLine.fileDescrRight.fileSize; objectsToOverwrite = 1; - break; - case SyncConfiguration::SYNC_DIR_RIGHT: //copy from left to right + return true; + case SYNC_DIR_RIGHT: //copy from left to right dataToProcess = fileCmpLine.fileDescrLeft.fileSize; objectsToOverwrite = 1; - break; - case SyncConfiguration::SYNC_DIR_NONE: + return true; + case SYNC_UNRESOLVED_CONFLICT: + conflicts = 1; + return true; + case SYNC_DIR_NONE: return false; } - break; case FILE_EQUAL: return false; - - default: - assert(false); - return false; }; - return true; + return true; //dummy } //runs at folder pair level void calcBytesToSync(const FileComparison& fileCmp, - const SyncConfiguration& config, int& objectsToCreate, int& objectsToOverwrite, int& objectsToDelete, + int& conflicts, wxULongLong& dataToProcess) { objectsToCreate = 0; objectsToOverwrite = 0; objectsToDelete = 0; + conflicts = 0; dataToProcess = 0; - int toCreate = 0; - int toOverwrite = 0; - int toDelete = 0; + int toCreate = 0; + int toOverwrite = 0; + int toDelete = 0; + int newConflicts = 0; wxULongLong data; for (FileComparison::const_iterator i = fileCmp.begin(); i != fileCmp.end(); ++i) { //only sum up sizes of files AND directories - if (getBytesToTransfer(*i, config, toCreate, toOverwrite, toDelete, data)) + if (getBytesToTransfer(*i, toCreate, toOverwrite, toDelete, newConflicts, data)) { objectsToCreate += toCreate; objectsToOverwrite += toOverwrite; objectsToDelete += toDelete; + conflicts += newConflicts; dataToProcess += data; } } @@ -165,15 +143,16 @@ void calcBytesToSync(const FileComparison& fileCmp, //aggregate over all folder pairs void FreeFileSync::calcTotalBytesToSync(const FolderComparison& folderCmp, - const SyncConfiguration& config, int& objectsToCreate, int& objectsToOverwrite, int& objectsToDelete, + int& conflicts, wxULongLong& dataToProcess) { objectsToCreate = 0; objectsToOverwrite = 0; objectsToDelete = 0; + conflicts = 0; dataToProcess = 0; for (FolderComparison::const_iterator j = folderCmp.begin(); j != folderCmp.end(); ++j) @@ -183,20 +162,22 @@ void FreeFileSync::calcTotalBytesToSync(const FolderComparison& folderCmp, int toCreate = 0; int toOverwrite = 0; int toDelete = 0; + int newConflics = 0; wxULongLong data; - calcBytesToSync(fileCmp, config, toCreate, toOverwrite, toDelete, data); + calcBytesToSync(fileCmp, toCreate, toOverwrite, toDelete, newConflics, data); objectsToCreate += toCreate; objectsToOverwrite += toOverwrite; objectsToDelete += toDelete; + conflicts += newConflics; dataToProcess += data; } } template <bool recyclerUsed> -std::pair<wxLongLong, wxLongLong> spaceNeededSub(const FileComparison& fileCmp, const SyncConfiguration& config) +std::pair<wxLongLong, wxLongLong> spaceNeededSub(const FileComparison& fileCmp) { wxLongLong spaceNeededLeft; wxLongLong spaceNeededRight; @@ -206,21 +187,22 @@ std::pair<wxLongLong, wxLongLong> spaceNeededSub(const FileComparison& fileCmp, if (i->selectedForSynchronization) //do not add filtered entries { //get data to process - switch (getSyncDirection(i->cmpResult, config)) + switch (i->direction) { - case SyncConfiguration::SYNC_DIR_LEFT: //copy from right to left + case SYNC_DIR_LEFT: //copy from right to left if (!recyclerUsed) spaceNeededLeft -= globalFunctions::convertToSigned(i->fileDescrLeft.fileSize); spaceNeededLeft += globalFunctions::convertToSigned(i->fileDescrRight.fileSize); break; - case SyncConfiguration::SYNC_DIR_RIGHT: //copy from left to right + case SYNC_DIR_RIGHT: //copy from left to right if (!recyclerUsed) spaceNeededRight -= globalFunctions::convertToSigned(i->fileDescrRight.fileSize); spaceNeededRight += globalFunctions::convertToSigned(i->fileDescrLeft.fileSize); break; - case SyncConfiguration::SYNC_DIR_NONE: + case SYNC_DIR_NONE: + case SYNC_UNRESOLVED_CONFLICT: break; } } @@ -230,49 +212,108 @@ std::pair<wxLongLong, wxLongLong> spaceNeededSub(const FileComparison& fileCmp, } -std::pair<wxLongLong, wxLongLong> freeDiskSpaceNeeded(const FileComparison& fileCmp, const SyncConfiguration& config, const bool recyclerUsed) +std::pair<wxLongLong, wxLongLong> freeDiskSpaceNeeded(const FileComparison& fileCmp, const bool recyclerUsed) { if (recyclerUsed) - return spaceNeededSub<true>(fileCmp, config); + return spaceNeededSub<true>(fileCmp); else - return spaceNeededSub<false>(fileCmp, config); + return spaceNeededSub<false>(fileCmp); +} + + +bool unresolvedConflictsExisting(const FolderComparison& folderCmp) +{ + for (FolderComparison::const_iterator j = folderCmp.begin(); j != folderCmp.end(); ++j) + { + const FileComparison& fileCmp = j->fileCmp; + for (FileComparison::const_iterator i = fileCmp.begin(); i != fileCmp.end(); ++i) + if (i->direction == SYNC_UNRESOLVED_CONFLICT) + return true; + } + return false; } -bool FreeFileSync::synchronizationNeeded(const FolderComparison& folderCmp, const SyncConfiguration& config) +bool FreeFileSync::synchronizationNeeded(const FolderComparison& folderCmp) { int objectsToCreate = 0; int objectsToOverwrite = 0; int objectsToDelete = 0; + int conflicts = 0; wxULongLong dataToProcess; FreeFileSync::calcTotalBytesToSync(folderCmp, - config, objectsToCreate, objectsToOverwrite, objectsToDelete, + conflicts, dataToProcess); - return objectsToCreate + objectsToOverwrite + objectsToDelete != 0; + return objectsToCreate + objectsToOverwrite + objectsToDelete + conflicts != 0; +} + + +void FreeFileSync::redetermineSyncDirection(const SyncConfiguration& config, FolderComparison& folderCmp) +{ + //do not handle i->selectedForSynchronization in this method! handled in synchronizeFile(), synchronizeFolder()! + + + for (FolderComparison::iterator j = folderCmp.begin(); j != folderCmp.end(); ++j) + { + FileComparison& fileCmp = j->fileCmp; + for (FileComparison::iterator i = fileCmp.begin(); i != fileCmp.end(); ++i) + { + switch (i->cmpResult) + { + case FILE_LEFT_SIDE_ONLY: + i->direction = config.exLeftSideOnly; + break; + + case FILE_RIGHT_SIDE_ONLY: + i->direction = config.exRightSideOnly; + break; + + case FILE_RIGHT_NEWER: + i->direction = config.rightNewer; + break; + + case FILE_LEFT_NEWER: + i->direction = config.leftNewer; + break; + + case FILE_DIFFERENT: + i->direction = config.different; + break; + + case FILE_CONFLICT: + i->direction = SYNC_UNRESOLVED_CONFLICT; + break; + + case FILE_EQUAL: + i->direction = SYNC_DIR_NONE; + } + } + } } //test if more then 50% of files will be deleted/overwritten -bool significantDifferenceDetected(const FileComparison& fileCmp, const SyncConfiguration& config) +bool significantDifferenceDetected(const FileComparison& fileCmp) { int objectsToCreate = 0; int objectsToOverwrite = 0; int objectsToDelete = 0; + int conflicts = 0; wxULongLong dataToProcess; calcBytesToSync(fileCmp, - config, objectsToCreate, objectsToOverwrite, objectsToDelete, + conflicts, dataToProcess); - const int changedFiles = objectsToCreate + objectsToOverwrite + objectsToDelete; //include objectsToCreate also! + const int changedFiles = objectsToCreate + objectsToOverwrite + objectsToDelete + conflicts; //include objectsToCreate also! return changedFiles >= 10 && changedFiles > 0.5 * fileCmp.size(); } @@ -283,12 +324,14 @@ SyncProcess::SyncProcess(const bool useRecycler, const bool traverseDirSymLinks, bool& warningSignificantDifference, bool& warningNotEnoughDiskSpace, + bool& warningUnresolvedConflict, StatusHandler* handler) : m_useRecycleBin(useRecycler), m_copyFileSymLinks(copyFileSymLinks), m_traverseDirSymLinks(traverseDirSymLinks), m_warningSignificantDifference(warningSignificantDifference), m_warningNotEnoughDiskSpace(warningNotEnoughDiskSpace), + m_warningUnresolvedConflict(warningUnresolvedConflict), statusUpdater(handler), txtCopyingFile(Zstring(_("Copying file %x to %y")).Replace(wxT("%x"), wxT("\"%x\""), false).Replace(wxT("%y"), wxT("\n\"%y\""), false)), txtOverwritingFile(Zstring(_("Copying file %x to %y overwriting target")).Replace(wxT("%x"), wxT("\"%x\""), false).Replace(wxT("%y"), wxT("\n\"%y\""), false)), @@ -298,7 +341,7 @@ SyncProcess::SyncProcess(const bool useRecycler, inline -bool SyncProcess::synchronizeFile(const FileCompareLine& cmpLine, const SyncConfiguration& config, const FolderPair& folderPair) +bool SyncProcess::synchronizeFile(const FileCompareLine& cmpLine, const FolderPair& folderPair) { //return false if nothing had to be done if (!cmpLine.selectedForSynchronization) return false; @@ -310,16 +353,16 @@ bool SyncProcess::synchronizeFile(const FileCompareLine& cmpLine, const SyncConf switch (cmpLine.cmpResult) { case FILE_LEFT_SIDE_ONLY: - switch (config.exLeftSideOnly) + switch (cmpLine.direction) { - case SyncConfiguration::SYNC_DIR_LEFT: //delete files on left + case SYNC_DIR_LEFT: //delete files on left statusText = txtDeletingFile; statusText.Replace(wxT("%x"), cmpLine.fileDescrLeft.fullName, false); statusUpdater->updateStatusText(statusText); removeFile(cmpLine.fileDescrLeft.fullName, m_useRecycleBin); - break; - case SyncConfiguration::SYNC_DIR_RIGHT: //copy files to right + return true; + case SYNC_DIR_RIGHT: //copy files to right target = folderPair.rightDirectory + cmpLine.fileDescrLeft.relativeName.c_str(); statusText = txtCopyingFile; @@ -328,16 +371,16 @@ bool SyncProcess::synchronizeFile(const FileCompareLine& cmpLine, const SyncConf statusUpdater->updateStatusText(statusText); copyFileUpdating(cmpLine.fileDescrLeft.fullName, target, cmpLine.fileDescrLeft.fileSize); - break; - case SyncConfiguration::SYNC_DIR_NONE: + return true; + case SYNC_DIR_NONE: + case SYNC_UNRESOLVED_CONFLICT: return false; } - break; case FILE_RIGHT_SIDE_ONLY: - switch (config.exRightSideOnly) + switch (cmpLine.direction) { - case SyncConfiguration::SYNC_DIR_LEFT: //copy files to left + case SYNC_DIR_LEFT: //copy files to left target = folderPair.leftDirectory + cmpLine.fileDescrRight.relativeName.c_str(); statusText = txtCopyingFile; @@ -346,25 +389,26 @@ bool SyncProcess::synchronizeFile(const FileCompareLine& cmpLine, const SyncConf statusUpdater->updateStatusText(statusText); copyFileUpdating(cmpLine.fileDescrRight.fullName, target, cmpLine.fileDescrRight.fileSize); - break; - case SyncConfiguration::SYNC_DIR_RIGHT: //delete files on right + return true; + case SYNC_DIR_RIGHT: //delete files on right statusText = txtDeletingFile; statusText.Replace(wxT("%x"), cmpLine.fileDescrRight.fullName, false); statusUpdater->updateStatusText(statusText); removeFile(cmpLine.fileDescrRight.fullName, m_useRecycleBin); - break; - case SyncConfiguration::SYNC_DIR_NONE: + return true; + case SYNC_DIR_NONE: + case SYNC_UNRESOLVED_CONFLICT: return false; } - break; case FILE_LEFT_NEWER: case FILE_RIGHT_NEWER: case FILE_DIFFERENT: - switch (getSyncDirection(cmpLine.cmpResult, config)) + case FILE_CONFLICT: + switch (cmpLine.direction) { - case SyncConfiguration::SYNC_DIR_LEFT: //copy from right to left + case SYNC_DIR_LEFT: //copy from right to left statusText = txtOverwritingFile; statusText.Replace(wxT("%x"), cmpLine.fileDescrRight.fullName.AfterLast(GlobalResources::FILE_NAME_SEPARATOR), false); statusText.Replace(wxT("%y"), cmpLine.fileDescrLeft.fullName.BeforeLast(GlobalResources::FILE_NAME_SEPARATOR), false); @@ -372,8 +416,8 @@ bool SyncProcess::synchronizeFile(const FileCompareLine& cmpLine, const SyncConf removeFile(cmpLine.fileDescrLeft.fullName, m_useRecycleBin); //only used if switch activated by user, else file is simply deleted copyFileUpdating(cmpLine.fileDescrRight.fullName, cmpLine.fileDescrLeft.fullName, cmpLine.fileDescrRight.fileSize); - break; - case SyncConfiguration::SYNC_DIR_RIGHT: //copy from left to right + return true; + case SYNC_DIR_RIGHT: //copy from left to right statusText = txtOverwritingFile; statusText.Replace(wxT("%x"), cmpLine.fileDescrLeft.fullName.AfterLast(GlobalResources::FILE_NAME_SEPARATOR), false); statusText.Replace(wxT("%y"), cmpLine.fileDescrRight.fullName.BeforeLast(GlobalResources::FILE_NAME_SEPARATOR), false); @@ -381,24 +425,22 @@ bool SyncProcess::synchronizeFile(const FileCompareLine& cmpLine, const SyncConf removeFile(cmpLine.fileDescrRight.fullName, m_useRecycleBin); //only used if switch activated by user, else file is simply deleted copyFileUpdating(cmpLine.fileDescrLeft.fullName, cmpLine.fileDescrRight.fullName, cmpLine.fileDescrLeft.fileSize); - break; - case SyncConfiguration::SYNC_DIR_NONE: + return true; + case SYNC_DIR_NONE: + case SYNC_UNRESOLVED_CONFLICT: return false; } - break; case FILE_EQUAL: return false; - - default: - assert (false); } - return true; + + return false; //dummy } inline -bool SyncProcess::synchronizeFolder(const FileCompareLine& cmpLine, const SyncConfiguration& config, const FolderPair& folderPair) +bool SyncProcess::synchronizeFolder(const FileCompareLine& cmpLine, const FolderPair& folderPair) { //return false if nothing had to be done if (!cmpLine.selectedForSynchronization) return false; @@ -410,16 +452,16 @@ bool SyncProcess::synchronizeFolder(const FileCompareLine& cmpLine, const SyncCo switch (cmpLine.cmpResult) { case FILE_LEFT_SIDE_ONLY: - switch (config.exLeftSideOnly) + switch (cmpLine.direction) { - case SyncConfiguration::SYNC_DIR_LEFT: //delete folders on left + case SYNC_DIR_LEFT: //delete folders on left statusText = txtDeletingFolder; statusText.Replace(wxT("%x"), cmpLine.fileDescrLeft.fullName, false); statusUpdater->updateStatusText(statusText); removeDirectory(cmpLine.fileDescrLeft.fullName, m_useRecycleBin); - break; - case SyncConfiguration::SYNC_DIR_RIGHT: //create folders on right + return true; + case SYNC_DIR_RIGHT: //create folders on right target = folderPair.rightDirectory + cmpLine.fileDescrLeft.relativeName.c_str(); statusText = txtCreatingFolder; @@ -430,16 +472,16 @@ bool SyncProcess::synchronizeFolder(const FileCompareLine& cmpLine, const SyncCo if (!wxDirExists(cmpLine.fileDescrLeft.fullName)) throw FileError(Zstring(_("Error: Source directory does not exist anymore:")) + wxT("\n\"") + cmpLine.fileDescrLeft.fullName + wxT("\"")); createDirectory(target, cmpLine.fileDescrLeft.fullName, !m_traverseDirSymLinks); //traverse symlinks <=> !copy symlinks - break; - case SyncConfiguration::SYNC_DIR_NONE: + return true; + case SYNC_DIR_NONE: + case SYNC_UNRESOLVED_CONFLICT: return false; } - break; case FILE_RIGHT_SIDE_ONLY: - switch (config.exRightSideOnly) + switch (cmpLine.direction) { - case SyncConfiguration::SYNC_DIR_LEFT: //create folders on left + case SYNC_DIR_LEFT: //create folders on left target = folderPair.leftDirectory + cmpLine.fileDescrRight.relativeName.c_str(); statusText = txtCreatingFolder; @@ -450,18 +492,18 @@ bool SyncProcess::synchronizeFolder(const FileCompareLine& cmpLine, const SyncCo if (!wxDirExists(cmpLine.fileDescrRight.fullName)) throw FileError(Zstring(_("Error: Source directory does not exist anymore:")) + wxT("\n\"") + cmpLine.fileDescrRight.fullName + wxT("\"")); createDirectory(target, cmpLine.fileDescrRight.fullName, !m_traverseDirSymLinks); //traverse symlinks <=> !copy symlinks - break; - case SyncConfiguration::SYNC_DIR_RIGHT: //delete folders on right + return true; + case SYNC_DIR_RIGHT: //delete folders on right statusText = txtDeletingFolder; statusText.Replace(wxT("%x"), cmpLine.fileDescrRight.fullName, false); statusUpdater->updateStatusText(statusText); removeDirectory(cmpLine.fileDescrRight.fullName, m_useRecycleBin); - break; - case SyncConfiguration::SYNC_DIR_NONE: + return true; + case SYNC_DIR_NONE: + case SYNC_UNRESOLVED_CONFLICT: return false; } - break; case FILE_EQUAL: return false; @@ -469,18 +511,20 @@ bool SyncProcess::synchronizeFolder(const FileCompareLine& cmpLine, const SyncCo case FILE_RIGHT_NEWER: case FILE_LEFT_NEWER: case FILE_DIFFERENT: - default: + case FILE_CONFLICT: assert (false); + return false; } - return true; + + return false; //dummy } inline -bool deletionImminent(const FileCompareLine& line, const SyncConfiguration& config) +bool deletionImminent(const FileCompareLine& line) { //test if current sync-line will result in deletion of files -> used to avoid disc space bottlenecks - if ( (line.cmpResult == FILE_LEFT_SIDE_ONLY && config.exLeftSideOnly == SyncConfiguration::SYNC_DIR_LEFT) || - (line.cmpResult == FILE_RIGHT_SIDE_ONLY && config.exRightSideOnly == SyncConfiguration::SYNC_DIR_RIGHT)) + if ( (line.cmpResult == FILE_LEFT_SIDE_ONLY && line.direction == SYNC_DIR_LEFT) || + (line.cmpResult == FILE_RIGHT_SIDE_ONLY && line.direction == SYNC_DIR_RIGHT)) return true; else return false; @@ -510,12 +554,30 @@ private: //synchronize and returns all rows that have not been synced -void SyncProcess::startSynchronizationProcess(FolderComparison& folderCmp, const SyncConfiguration& config) +void SyncProcess::startSynchronizationProcess(FolderComparison& folderCmp) { #ifndef __WXDEBUG__ wxLogNull noWxLogs; //prevent wxWidgets logging #endif + //inform about the total amount of data that will be processed from now on + int objectsToCreate = 0; + int objectsToOverwrite = 0; + int objectsToDelete = 0; + int conflicts = 0; + wxULongLong dataToProcess; + + FreeFileSync::calcTotalBytesToSync(folderCmp, + objectsToCreate, + objectsToOverwrite, + objectsToDelete, + conflicts, + dataToProcess); + + statusUpdater->initNewProcess(objectsToCreate + objectsToOverwrite + objectsToDelete, //keep at beginning so that all gui elements are initialized properly + globalFunctions::convertToSigned(dataToProcess), + StatusHandler::PROCESS_SYNCHRONIZING); + //-------------------some basic checks:------------------------------------------ //test existence of Recycle Bin @@ -532,7 +594,7 @@ void SyncProcess::startSynchronizationProcess(FolderComparison& folderCmp, const //check if more than 50% of total number of files/dirs are to be created/overwritten/deleted if (m_warningSignificantDifference) //test if check should be executed { - if (significantDifferenceDetected(fileCmp, config)) + if (significantDifferenceDetected(fileCmp)) { bool dontShowAgain = false; statusUpdater->reportWarning(Zstring(_("Significant difference detected:")) + wxT("\n") + @@ -546,7 +608,7 @@ void SyncProcess::startSynchronizationProcess(FolderComparison& folderCmp, const //check for sufficient free diskspace in left directory if (m_warningNotEnoughDiskSpace) { - const std::pair<wxLongLong, wxLongLong> spaceNeeded = freeDiskSpaceNeeded(fileCmp, config, m_useRecycleBin); + const std::pair<wxLongLong, wxLongLong> spaceNeeded = freeDiskSpaceNeeded(fileCmp, m_useRecycleBin); wxLongLong freeDiskSpaceLeft; if (wxGetDiskSpace(j->syncPair.leftDirectory.c_str(), NULL, &freeDiskSpaceLeft)) @@ -581,25 +643,21 @@ void SyncProcess::startSynchronizationProcess(FolderComparison& folderCmp, const } } } - //-------------------end of basic checks------------------------------------------ + //check if unresolved conflicts exist + if (m_warningUnresolvedConflict) //test if check should be executed + { + if (conflicts > 0) + { + bool dontShowAgain = false; + statusUpdater->reportWarning(_("Unresolved conflicts existing! \n\nYou can ignore conflicts and continue synchronization."), + dontShowAgain); + m_warningUnresolvedConflict = !dontShowAgain; + } + } - //inform about the total amount of data that will be processed from now on - int objectsToCreate = 0; - int objectsToOverwrite = 0; - int objectsToDelete = 0; - wxULongLong dataToProcess; - - FreeFileSync::calcTotalBytesToSync(folderCmp, - config, - objectsToCreate, - objectsToOverwrite, - objectsToDelete, - dataToProcess); + //-------------------end of basic checks------------------------------------------ - statusUpdater->initNewProcess(objectsToCreate + objectsToOverwrite + objectsToDelete, - globalFunctions::convertToSigned(dataToProcess), - StatusHandler::PROCESS_SYNCHRONIZING); try { @@ -629,7 +687,7 @@ void SyncProcess::startSynchronizationProcess(FolderComparison& folderCmp, const try { - if (synchronizeFolder(*i, config, currentPair)) + if (synchronizeFolder(*i, currentPair)) //progress indicator update //indicator is updated only if directory is sync'ed correctly (and if some work was done)! statusUpdater->updateProcessedData(1, 0); //each call represents one processed file/directory @@ -662,11 +720,15 @@ void SyncProcess::startSynchronizationProcess(FolderComparison& folderCmp, const for (FileComparison::const_iterator i = fileCmp.begin(); i != fileCmp.end(); ++i) { + //skip processing of unresolved errors (do not remove row from GUI grid) + if (i->direction == SYNC_UNRESOLVED_CONFLICT && i->selectedForSynchronization) + continue; + if ( i->fileDescrLeft.objType == FileDescrLine::TYPE_FILE || i->fileDescrRight.objType == FileDescrLine::TYPE_FILE) { - if ( (deleteLoop && deletionImminent(*i, config)) || - (!deleteLoop && !deletionImminent(*i, config))) + if ( (deleteLoop && deletionImminent(*i)) || + (!deleteLoop && !deletionImminent(*i))) { while (true) { //trigger display refresh @@ -674,20 +736,21 @@ void SyncProcess::startSynchronizationProcess(FolderComparison& folderCmp, const try { - if (synchronizeFile(*i, config, currentPair)) + if (synchronizeFile(*i, currentPair)) { //progress indicator update //indicator is updated only if file is sync'ed correctly (and if some sync was done)! int objectsToCreate = 0; int objectsToOverwrite = 0; int objectsToDelete = 0; + int conflictDummy = 0; wxULongLong dataToProcess; if (getBytesToTransfer(*i, - config, objectsToCreate, objectsToOverwrite, objectsToDelete, + conflictDummy, dataToProcess)) //update status if some work was done (answer is always "yes" in this context) statusUpdater->updateProcessedData(objectsToCreate + objectsToOverwrite + objectsToDelete, 0); //processed data is communicated in subfunctions! } diff --git a/synchronization.h b/synchronization.h index c8ce10cd..47052fac 100644 --- a/synchronization.h +++ b/synchronization.h @@ -9,13 +9,15 @@ class StatusHandler; namespace FreeFileSync { void calcTotalBytesToSync(const FolderComparison& folderCmp, - const SyncConfiguration& config, int& objectsToCreate, int& objectsToOverwrite, int& objectsToDelete, + int& conflicts, wxULongLong& dataToProcess); - bool synchronizationNeeded(const FolderComparison& folderCmp, const SyncConfiguration& config); + bool synchronizationNeeded(const FolderComparison& folderCmp); + + void redetermineSyncDirection(const SyncConfiguration& config, FolderComparison& folderCmp); //class handling synchronization process class SyncProcess @@ -26,21 +28,26 @@ namespace FreeFileSync const bool traverseDirSymLinks, bool& warningSignificantDifference, bool& warningNotEnoughDiskSpace, + bool& warningUnresolvedConflict, StatusHandler* handler); - void startSynchronizationProcess(FolderComparison& folderCmp, const SyncConfiguration& config); + void startSynchronizationProcess(FolderComparison& folderCmp); private: - bool synchronizeFile(const FileCompareLine& cmpLine, const SyncConfiguration& config, const FolderPair& folderPair); //false if nothing was done - bool synchronizeFolder(const FileCompareLine& cmpLine, const SyncConfiguration& config, const FolderPair& folderPair); //false if nothing was done + bool synchronizeFile(const FileCompareLine& cmpLine, const FolderPair& folderPair); //false if nothing was done + bool synchronizeFolder(const FileCompareLine& cmpLine, const FolderPair& folderPair); //false if nothing was done void copyFileUpdating(const Zstring& source, const Zstring& target, const wxULongLong& sourceFileSize); const bool m_useRecycleBin; const bool m_copyFileSymLinks; const bool m_traverseDirSymLinks; + + //warnings bool& m_warningSignificantDifference; bool& m_warningNotEnoughDiskSpace; + bool& m_warningUnresolvedConflict; + StatusHandler* statusUpdater; //preload status texts diff --git a/ui/MainDialog.cpp b/ui/MainDialog.cpp index e8006600..32a1e124 100644 --- a/ui/MainDialog.cpp +++ b/ui/MainDialog.cpp @@ -57,8 +57,7 @@ public: //test if ffs config file has been dropped if (fileType == xmlAccess::XML_GUI_CONFIG) { - if (mainDlg_->readConfigurationFromXml(dropName)) - mainDlg_->pushStatusInformation(_("Configuration loaded!")); + mainDlg_->loadConfiguration(dropName); return false; } //...or a ffs batch file @@ -71,7 +70,7 @@ public: } //disable the sync button - mainDlg_->enableSynchronization(false); + mainDlg_->syncPreview->enableSynchronization(false); //clear grids mainDlg_->currentGridData.clear(); @@ -133,13 +132,11 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale gridDataView(currentGridData), contextMenu(new wxMenu), //initialize right-click context menu; will be dynamically re-created on each R-mouse-click programLanguage(language), - filteringInitialized(false), - filteringPending(false), - synchronizationEnabled(false), cmpStatusHandlerTmp(0), cleanedUp(false), lastSortColumn(-1), - lastSortGrid(NULL) + lastSortGrid(NULL), + syncPreview(new SyncPreview(this)) { //initialize and load configuration readGlobalSettings(); @@ -148,14 +145,17 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale //set icons for this dialog m_bpButton10->SetBitmapLabel(*globalResource.bitmapExit); m_buttonCompare->setBitmapFront(*globalResource.bitmapCompare); - m_buttonSync->setBitmapFront(*globalResource.bitmapSync); - m_bpButtonSwap->SetBitmapLabel(*globalResource.bitmapSwap); + m_bpButtonSyncConfig->SetBitmapLabel(*globalResource.bitmapSyncCfg); m_bpButton14->SetBitmapLabel(*globalResource.bitmapHelp); m_bpButtonSave->SetBitmapLabel(*globalResource.bitmapSave); m_bpButtonLoad->SetBitmapLabel(*globalResource.bitmapLoad); m_bpButtonAddPair->SetBitmapLabel(*globalResource.bitmapAddFolderPair); m_bitmap15->SetBitmap(*globalResource.bitmapStatusEdge); m_bitmapShift->SetBitmap(*globalResource.bitmapShift); + m_bitmapCreate->SetBitmap(*globalResource.bitmapCreate); + m_bitmapUpdate->SetBitmap(*globalResource.bitmapUpdate); + m_bitmapDelete->SetBitmap(*globalResource.bitmapDelete); + m_bitmapData->SetBitmap(*globalResource.bitmapData); bSizer6->Layout(); //wxButtonWithImage size might have changed @@ -163,6 +163,7 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale MenuItemUpdater updateMenuFile(m_menuFile); updateMenuFile.addForUpdate(m_menuItem10, *globalResource.bitmapCompareSmall); updateMenuFile.addForUpdate(m_menuItem11, *globalResource.bitmapSyncSmall); + updateMenuFile.addForUpdate(m_menuItemSwitchView, *globalResource.bitmapSwitchViewSmall); MenuItemUpdater updateMenuAdv(m_menuAdvanced); updateMenuAdv.addForUpdate(m_menuItemGlobSett, *globalResource.bitmapSettingsSmall); @@ -208,12 +209,13 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale m_gridMiddle->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(MainDialog::onGridMiddleButtonEvent), NULL, this); Connect(wxEVT_IDLE, wxEventHandler(MainDialog::OnIdleEvent), NULL, this); - m_gridMiddle->GetGridWindow()->Connect(wxEVT_LEFT_UP, wxEventHandler(MainDialog::OnGrid3LeftMouseUp), NULL, this); - m_gridMiddle->GetGridWindow()->Connect(wxEVT_LEFT_DOWN, wxEventHandler(MainDialog::OnGrid3LeftMouseDown), NULL, this); - Connect(wxEVT_SIZE, wxEventHandler(MainDialog::onResizeMainWindow), NULL, this); Connect(wxEVT_MOVE, wxEventHandler(MainDialog::onResizeMainWindow), NULL, this); + //event handler for manual (un-)checking of rows and setting of sync direction + m_gridMiddle->Connect(FFS_CHECK_ROWS_EVENT, FFSCheckRowsEventHandler(MainDialog::OnCheckRows), NULL, this); + m_gridMiddle->Connect(FFS_SYNC_DIRECTION_EVENT, FFSSyncDirectionEventHandler(MainDialog::OnSetSyncDirection), NULL, this); + //init grid settings m_gridLeft->initSettings( globalSettings.gui.showFileIcons, m_gridLeft, @@ -233,13 +235,11 @@ MainDialog::MainDialog(wxFrame* frame, const wxString& cfgFileName, CustomLocale &gridDataView); //disable sync button as long as "compare" hasn't been triggered. - enableSynchronization(false); + syncPreview->enableSynchronization(false); //mainly to update row label sizes... updateGuiGrid(); - enableSynchronization(false); - //create the compare status panel in hidden state compareStatus = new CompareStatus(this); bSizer1->Insert(1, compareStatus, 0, wxEXPAND | wxBOTTOM, 5 ); @@ -347,31 +347,13 @@ void MainDialog::writeGlobalSettings() } -void MainDialog::enableSynchronization(bool value) -{ - if (value) - { - synchronizationEnabled = true; - m_buttonSync->SetForegroundColour(*wxBLACK); - m_buttonSync->setBitmapFront(*globalResource.bitmapSync); - } - else - { - synchronizationEnabled = false; - m_buttonSync->SetForegroundColour(wxColor(94, 94, 94)); //grey - m_buttonSync->setBitmapFront(*globalResource.bitmapSyncDisabled); - } -} - - -void MainDialog::filterRangeManually(const std::set<int>& rowsToFilterOnUiTable) +void MainDialog::filterRangeManually(const std::set<int>& rowsToFilterOnUiTable, const int leadingRow) { if (rowsToFilterOnUiTable.size() > 0) { bool newSelection = false; //default: deselect range //leadingRow determines de-/selection of all other rows - const int leadingRow = *rowsToFilterOnUiTable.begin(); if (0 <= leadingRow && leadingRow < int(gridDataView.elementsOnView())) newSelection = !gridDataView[leadingRow].selectedForSynchronization; @@ -414,67 +396,15 @@ void MainDialog::filterRangeManually(const std::set<int>& rowsToFilterOnUiTable) m_gridLeft->ClearSelection(); m_gridRight->ClearSelection(); - m_gridMiddle->ClearSelection(); } else - { //this second call to ForceRefresh() looks strange, but it actually fixes occasional graphical artifacts on bottom right of the grid - m_gridLeft->ForceRefresh(); - m_gridMiddle->ForceRefresh(); - m_gridRight->ForceRefresh(); - - m_gridMiddle->ClearSelection(); - } + updateGuiGrid(); } } -/*grid event choreography: -1. UI-Mouse-Down => OnGridSelectCell -2. UI-Mouse-Up => SelectRangeEvent (if at least two rows are marked) - -=> the decision if a range or a single cell is selected can be made only after Mouse-UP. But SelectRangeEvent unfortunately is not always -executed (e.g. if single cell selected) - -=> new choreography: -1. UI-Mouse-Down => OnGrid3LeftMouseDown (notify that filtering was initialized: this is needed since under some circumstances it might happen that the program - receives a mouse-up without a preceding mouse-down (double-clicks) -2. UI-Mouse-Up => OnGrid3LeftMouseUp (notify that filtering shall be started on next idle event -3. UI-Mouse-Up => SelectRangeEvent, possibly -4. Idle event => OnIdleEvent -*/ - - -void MainDialog::OnGrid3LeftMouseDown(wxEvent& event) -{ - filteringInitialized = true; - event.Skip(); -} - - -void MainDialog::OnGrid3LeftMouseUp(wxEvent& event) -{ - filteringPending = true; - event.Skip(); -} - void MainDialog::OnIdleEvent(wxEvent& event) { - //process manually filtered rows - if (filteringPending) - { - filteringPending = false; - - if (filteringInitialized) //filteringInitialized is being reset after each selection, since strangely it might happen, that the grid receives - { //a mouse up event, but no mouse down! (e.g. when window is maximized and cursor is on grid3) - filteringInitialized = false; - - if (m_gridMiddle) - filterRangeManually(getSelectedRows(m_gridMiddle)); - } - } - - //------------------------------------------------------------------------------ - //small routine to restore status information after some time if (stackObjects.size() > 0 ) //check if there is some work to do { @@ -538,54 +468,9 @@ void removeInvalidRows(std::set<int>& rows, const int currentUiTableSize) } -std::set<int> MainDialog::getSelectedRows(const CustomGrid* grid) +std::set<int> MainDialog::getSelectedRows(const CustomGrid* grid) const { - std::set<int> output; - int rowTop, rowBottom; //coords of selection - - wxArrayInt selectedRows = grid->GetSelectedRows(); - if (!selectedRows.IsEmpty()) - { - for (unsigned int i = 0; i < selectedRows.GetCount(); ++i) - output.insert(selectedRows[i]); - } - - if (!grid->GetSelectedCols().IsEmpty()) //if a column is selected this is means all rows are marked for deletion - { - for (int k = 0; k < const_cast<CustomGrid*>(grid)->GetNumberRows(); ++k) //messy wxGrid implementation... - output.insert(k); - } - - wxGridCellCoordsArray singlySelected = grid->GetSelectedCells(); - if (!singlySelected.IsEmpty()) - { - for (unsigned int k = 0; k < singlySelected.GetCount(); ++k) - output.insert(singlySelected[k].GetRow()); - } - - wxGridCellCoordsArray tmpArrayTop = grid->GetSelectionBlockTopLeft(); - if (!tmpArrayTop.IsEmpty()) - { - wxGridCellCoordsArray tmpArrayBottom = grid->GetSelectionBlockBottomRight(); - - unsigned int arrayCount = tmpArrayTop.GetCount(); - - if (arrayCount == tmpArrayBottom.GetCount()) - { - for (unsigned int i = 0; i < arrayCount; ++i) - { - rowTop = tmpArrayTop[i].GetRow(); - rowBottom = tmpArrayBottom[i].GetRow(); - - for (int k = rowTop; k <= rowBottom; ++k) - output.insert(k); - } - } - } - - //some exception: also add current cursor row to selection if there are no others... hopefully improving usability - if (output.empty() && grid->isLeadGrid()) - output.insert(const_cast<CustomGrid*>(grid)->GetCursorRow()); //messy wxGrid implementation... + std::set<int> output = grid->getAllSelectedRows(); removeInvalidRows(output, gridDataView.elementsOnView()); @@ -685,6 +570,7 @@ void MainDialog::deleteSelectedFiles() rowsToDeleteOnRight, globalSettings.gui.deleteOnBothSides, globalSettings.gui.useRecyclerForManualDeletion, + cfg.syncConfiguration, &errorHandler); } @@ -706,46 +592,76 @@ void MainDialog::openWithFileManager(const int rowNumber, const bool leftSide) { wxString command; - wxString defaultFolder; - if (0 <= rowNumber && rowNumber < int(gridDataView.elementsOnView())) - defaultFolder = leftSide ? - gridDataView.getFolderPair(rowNumber).leftDirectory.c_str() : - gridDataView.getFolderPair(rowNumber).rightDirectory.c_str(); - else - defaultFolder = leftSide ? - FreeFileSync::getFormattedDirectoryName(m_directoryLeft->GetValue().c_str()).c_str() : - FreeFileSync::getFormattedDirectoryName(m_directoryRight->GetValue().c_str()).c_str(); - -#ifdef FFS_WIN - command = wxString(wxT("explorer ")) + defaultFolder; //default -#elif defined FFS_LINUX - command = globalSettings.gui.commandLineFileManager; - command.Replace(wxT("%name"), defaultFolder); - command.Replace(wxT("%path"), defaultFolder); -#endif - if (0 <= rowNumber && rowNumber < int(gridDataView.elementsOnView())) { const FileDescrLine* fileDescr = leftSide ? &gridDataView[rowNumber].fileDescrLeft : &gridDataView[rowNumber].fileDescrRight; - if (fileDescr->objType == FileDescrLine::TYPE_FILE) + switch (fileDescr->objType) { + case FileDescrLine::TYPE_FILE: command = globalSettings.gui.commandLineFileManager; command.Replace(wxT("%name"), fileDescr->fullName.c_str()); command.Replace(wxT("%path"), wxString(fileDescr->fullName.c_str()).BeforeLast(GlobalResources::FILE_NAME_SEPARATOR)); - } - else if (fileDescr->objType == FileDescrLine::TYPE_DIRECTORY) - { + break; + case FileDescrLine::TYPE_DIRECTORY: command = globalSettings.gui.commandLineFileManager; command.Replace(wxT("%name"), fileDescr->fullName.c_str()); command.Replace(wxT("%path"), fileDescr->fullName.c_str()); - } - else if (fileDescr->objType == FileDescrLine::TYPE_NOTHING) + break; + case FileDescrLine::TYPE_NOTHING: { + //use path from other side + const FileDescrLine* fileDescrOther = leftSide ? + &gridDataView[rowNumber].fileDescrRight : + &gridDataView[rowNumber].fileDescrLeft; + + const wxString syncFolder = leftSide ? + gridDataView.getFolderPair(rowNumber).leftDirectory.c_str() : + gridDataView.getFolderPair(rowNumber).rightDirectory.c_str(); + + wxString alternateFolder; + switch (fileDescrOther->objType) + { + case FileDescrLine::TYPE_FILE: + alternateFolder = syncFolder + wxString(fileDescrOther->relativeName.c_str()).BeforeLast(GlobalResources::FILE_NAME_SEPARATOR); + break; + case FileDescrLine::TYPE_DIRECTORY: + alternateFolder = syncFolder + wxString(fileDescrOther->relativeName.c_str()); + break; + case FileDescrLine::TYPE_NOTHING: + assert(false); + break; + } + + if (!wxDirExists(alternateFolder)) + alternateFolder = syncFolder; + +#ifdef FFS_WIN + command = wxString(wxT("explorer ")) + alternateFolder; //default +#elif defined FFS_LINUX + command = globalSettings.gui.commandLineFileManager; + command.Replace(wxT("%name"), alternateFolder); + command.Replace(wxT("%path"), alternateFolder); +#endif + } + break; } } + else + { //fallback + const wxString defaultFolder = leftSide ? + FreeFileSync::getFormattedDirectoryName(m_directoryLeft->GetValue().c_str()).c_str() : + FreeFileSync::getFormattedDirectoryName(m_directoryRight->GetValue().c_str()).c_str(); +#ifdef FFS_WIN + command = wxString(wxT("explorer ")) + defaultFolder; //default +#elif defined FFS_LINUX + command = globalSettings.gui.commandLineFileManager; + command.Replace(wxT("%name"), defaultFolder); + command.Replace(wxT("%path"), defaultFolder); +#endif + } if (!command.empty()) wxExecute(command.c_str()); @@ -957,7 +873,6 @@ void MainDialog::OnContextMenu(wxGridEvent& event) //show context menu PopupMenu(contextMenu.get()); - event.Skip(); } @@ -972,7 +887,8 @@ void MainDialog::OnContextMenuSelection(wxCommandEvent& event) for (std::set<int>::const_iterator i = additional.begin(); i != additional.end(); ++i) selection.insert(*i); - filterRangeManually(selection); + if (selection.size() > 0) + filterRangeManually(selection, *selection.begin()); } else if (eventId == CONTEXT_EXCLUDE_EXT) @@ -987,7 +903,8 @@ void MainDialog::OnContextMenuSelection(wxCommandEvent& event) cfg.filterIsActive = true; updateFilterButton(m_bpButtonFilter, cfg.filterIsActive); - FreeFileSync::filterGridData(currentGridData, cfg.includeFilter, cfg.excludeFilter); + FreeFileSync::FilterProcess filterInstance(cfg.includeFilter, cfg.excludeFilter); + filterInstance.filterGridData(currentGridData); updateGuiGrid(); if (hideFilteredElements) @@ -1009,17 +926,17 @@ void MainDialog::OnContextMenuSelection(wxCommandEvent& event) cfg.excludeFilter+= wxT("\n"); if (i->type == FileDescrLine::TYPE_FILE) - cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::FILE_NAME_SEPARATOR + i->relativeName; + cfg.excludeFilter+= wxString(GlobalResources::FILE_NAME_SEPARATOR) + i->relativeName; else if (i->type == FileDescrLine::TYPE_DIRECTORY) - cfg.excludeFilter+= wxString(wxT("*")) + GlobalResources::FILE_NAME_SEPARATOR + i->relativeName + GlobalResources::FILE_NAME_SEPARATOR + wxT("*"); - + cfg.excludeFilter+= wxString(GlobalResources::FILE_NAME_SEPARATOR) + i->relativeName + GlobalResources::FILE_NAME_SEPARATOR + wxT("*"); else assert(false); } cfg.filterIsActive = true; updateFilterButton(m_bpButtonFilter, cfg.filterIsActive); - FreeFileSync::filterGridData(currentGridData, cfg.includeFilter, cfg.excludeFilter); + FreeFileSync::FilterProcess filterInstance(cfg.includeFilter, cfg.excludeFilter); + filterInstance.filterGridData(currentGridData); updateGuiGrid(); if (hideFilteredElements) @@ -1068,10 +985,12 @@ void MainDialog::OnContextMenuSelection(wxCommandEvent& event) void MainDialog::OnContextMenuMiddle(wxGridEvent& event) { contextMenu.reset(new wxMenu); //re-create context menu + contextMenu->Append(CONTEXT_SWAP_SIDES, _("Swap sides")); + contextMenu->AppendSeparator(); contextMenu->Append(CONTEXT_CHECK_ALL, _("Check all")); contextMenu->Append(CONTEXT_UNCHECK_ALL, _("Uncheck all")); - if (gridDataView.elementsTotal() == 0) + if (gridDataView.refGridIsEmpty()) { contextMenu->Enable(CONTEXT_CHECK_ALL, false); contextMenu->Enable(CONTEXT_UNCHECK_ALL, false); @@ -1079,22 +998,25 @@ void MainDialog::OnContextMenuMiddle(wxGridEvent& event) contextMenu->Connect(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(MainDialog::OnContextMenuMiddleSelection), NULL, this); PopupMenu(contextMenu.get()); //show context menu - - event.Skip(); } void MainDialog::OnContextMenuMiddleSelection(wxCommandEvent& event) { int eventId = event.GetId(); - if (eventId == CONTEXT_CHECK_ALL) + if (eventId == CONTEXT_SWAP_SIDES) + { + wxCommandEvent dummy; + MainDialog::OnSwapSides(dummy); + } + else if (eventId == CONTEXT_CHECK_ALL) { - FreeFileSync::includeAllRowsOnGrid(currentGridData); + FreeFileSync::FilterProcess::includeAllRowsOnGrid(currentGridData); updateGuiGrid(); } else if (eventId == CONTEXT_UNCHECK_ALL) { - FreeFileSync::excludeAllRowsOnGrid(currentGridData); + FreeFileSync::FilterProcess::excludeAllRowsOnGrid(currentGridData); updateGuiGrid(); } } @@ -1128,10 +1050,12 @@ void MainDialog::OnContextColumnSelection(wxCommandEvent& event) if (eventId == CONTEXT_CUSTOMIZE_COLUMN_LEFT) { xmlAccess::ColumnAttributes colAttr = m_gridLeft->getColumnAttributes(); - CustomizeColsDlg* customizeDlg = new CustomizeColsDlg(this, colAttr); + CustomizeColsDlg* customizeDlg = new CustomizeColsDlg(this, colAttr, globalSettings.gui.showFileIcons); if (customizeDlg->ShowModal() == CustomizeColsDlg::BUTTON_OKAY) { m_gridLeft->setColumnAttributes(colAttr); + m_gridLeft->enableFileIcons(globalSettings.gui.showFileIcons); + m_gridRight->enableFileIcons(globalSettings.gui.showFileIcons); m_gridLeft->setSortMarker(-1); //hide sort direction indicator on GUI grids m_gridMiddle->setSortMarker(-1); @@ -1141,10 +1065,13 @@ void MainDialog::OnContextColumnSelection(wxCommandEvent& event) else if (eventId == CONTEXT_CUSTOMIZE_COLUMN_RIGHT) { xmlAccess::ColumnAttributes colAttr = m_gridRight->getColumnAttributes(); - CustomizeColsDlg* customizeDlg = new CustomizeColsDlg(this, colAttr); + CustomizeColsDlg* customizeDlg = new CustomizeColsDlg(this, colAttr, globalSettings.gui.showFileIcons); if (customizeDlg->ShowModal() == CustomizeColsDlg::BUTTON_OKAY) { m_gridRight->setColumnAttributes(colAttr); + m_gridLeft->enableFileIcons(globalSettings.gui.showFileIcons); + m_gridRight->enableFileIcons(globalSettings.gui.showFileIcons); + m_gridLeft->setSortMarker(-1); //hide sort direction indicator on GUI grids m_gridMiddle->setSortMarker(-1); m_gridRight->setSortMarker(-1); @@ -1158,7 +1085,7 @@ void MainDialog::OnDirSelected(wxFileDirPickerEvent& event) //left and right directory text-control and dirpicker are synchronized by MainFolderDragDrop automatically //disable the sync button - enableSynchronization(false); + syncPreview->enableSynchronization(false); //clear grids currentGridData.clear(); @@ -1294,7 +1221,13 @@ void MainDialog::addRightFolderToHistory(const wxString& rightFolder) void MainDialog::OnSaveConfig(wxCommandEvent& event) { - const wxString defaultFileName = proposedConfigFileName.empty() ? wxT("SyncSettings.ffs_gui") : proposedConfigFileName; + trySaveConfig(); +} + + +bool MainDialog::trySaveConfig() //return true if saved successfully +{ + const wxString defaultFileName = currentConfigFileName.empty() ? wxT("SyncSettings.ffs_gui") : currentConfigFileName; wxFileDialog* filePicker = new wxFileDialog(this, wxEmptyString, wxEmptyString, defaultFileName, wxString(_("FreeFileSync configuration")) + wxT(" (*.ffs_gui)|*.ffs_gui"), wxFD_SAVE); if (filePicker->ShowModal() == wxID_OK) @@ -1306,14 +1239,17 @@ void MainDialog::OnSaveConfig(wxCommandEvent& event) wxMessageDialog* messageDlg = new wxMessageDialog(this, wxString(_("File already exists. Overwrite?")) + wxT(" \"") + newFileName + wxT("\""), _("Warning") , wxOK | wxCANCEL); if (messageDlg->ShowModal() != wxID_OK) - { - OnSaveConfig(event); //retry - return; - } + return trySaveConfig(); //retry } + if (writeConfigurationToXml(newFileName)) + { pushStatusInformation(_("Configuration saved!")); + return true; + } } + + return false; } @@ -1347,6 +1283,34 @@ void MainDialog::OnMenuLoadConfig(wxCommandEvent& event) void MainDialog::loadConfiguration(const wxString& filename) { + //notify user about changed settings + if (globalSettings.gui.popupOnConfigChange && !currentConfigFileName.empty()) //only if check is active and non-default config file loaded + { + if (lastConfigurationSaved != getCurrentConfiguration()) + { + bool dontShowAgain = !globalSettings.gui.popupOnConfigChange; + + QuestionDlg* notifyChangeDlg = new QuestionDlg(this, + QuestionDlg::BUTTON_YES | QuestionDlg::BUTTON_NO | QuestionDlg::BUTTON_CANCEL, + _("Save changes to current configuration?"), + dontShowAgain); + + switch (notifyChangeDlg->ShowModal()) + { + case QuestionDlg::BUTTON_YES: + if (!trySaveConfig()) + return; + break; + case QuestionDlg::BUTTON_NO: + globalSettings.gui.popupOnConfigChange = !dontShowAgain; + break; + case QuestionDlg::BUTTON_CANCEL: + return; + } + } + } + //------------------------------------------------------------------------------------ + if (!filename.IsEmpty()) { //clear grids currentGridData.clear(); @@ -1442,36 +1406,71 @@ void MainDialog::OnQuit(wxCommandEvent &event) void MainDialog::requestShutdown() { - /* - if (globalSettings.gui.popupOnConfigChange) + //notify user about changed settings + if (globalSettings.gui.popupOnConfigChange && !currentConfigFileName.empty()) //only if check is active and non-default config file loaded { if (lastConfigurationSaved != getCurrentConfiguration()) { - ... -wxID_OK - OnSaveConfig(wxCommandEvent& event) + bool dontShowAgain = !globalSettings.gui.popupOnConfigChange; + + QuestionDlg* notifyChangeDlg = new QuestionDlg(this, + QuestionDlg::BUTTON_YES | QuestionDlg::BUTTON_NO | QuestionDlg::BUTTON_CANCEL, + _("Save changes to current configuration?"), + dontShowAgain); - ; - wxMessageBox(wxT("ji")); + switch (notifyChangeDlg->ShowModal()) + { + case QuestionDlg::BUTTON_YES: + if (!trySaveConfig()) + return; + break; + case QuestionDlg::BUTTON_NO: + globalSettings.gui.popupOnConfigChange = !dontShowAgain; + break; + case QuestionDlg::BUTTON_CANCEL: + return; + } } } - */ Destroy(); } -bool MainDialog::readConfigurationFromXml(const wxString& filename, bool programStartup) +void MainDialog::OnCheckRows(FFSCheckRowsEvent& event) { - leftOnlyFilesActive = true; - leftNewerFilesActive = true; - differentFilesActive = true; - rightNewerFilesActive = true; //do not save/load these bool values from harddisk! - rightOnlyFilesActive = true; //it's more convenient to have them defaulted at startup - equalFilesActive = false; - updateViewFilterButtons(); + const int lowerBound = std::min(event.rowFrom, event.rowTo); + const int upperBound = std::max(event.rowFrom, event.rowTo); + if (0 <= lowerBound) + { + std::set<int> selectedRowsOnView; + + for (int i = lowerBound; i <= std::min(upperBound, int(gridDataView.elementsOnView()) - 1); ++i) + selectedRowsOnView.insert(i); + + filterRangeManually(selectedRowsOnView, event.rowFrom); + } +} + +void MainDialog::OnSetSyncDirection(FFSSyncDirectionEvent& event) +{ + const int lowerBound = std::min(event.rowFrom, event.rowTo); + const int upperBound = std::max(event.rowFrom, event.rowTo); + + if (0 <= lowerBound) + { + for (int i = lowerBound; i <= std::min(upperBound, int(gridDataView.elementsOnView()) - 1); ++i) + gridDataView[i].direction = event.direction; + + updateGuiGrid(); + } +} + + +bool MainDialog::readConfigurationFromXml(const wxString& filename, bool programStartup) +{ //load XML xmlAccess::XmlGuiConfig guiCfg; //structure to receive gui settings, already defaulted!! try @@ -1494,11 +1493,29 @@ bool MainDialog::readConfigurationFromXml(const wxString& filename, bool program } } + //(re-)set view filter buttons + gridDataView.leftOnlyFilesActive = true; + gridDataView.leftNewerFilesActive = true; + gridDataView.differentFilesActive = true; + gridDataView.rightNewerFilesActive = true; //do not save/load these bool values from harddisk! + gridDataView.rightOnlyFilesActive = true; //it's more convenient to have them defaulted at startup + gridDataView.equalFilesActive = false; + + gridDataView.conflictFilesActive = true; + + gridDataView.syncDirLeftActive = true; + gridDataView.syncDirRightActive = true; + gridDataView.syncDirNoneActive = true; + + updateViewFilterButtons(); + + //load main configuration into instance cfg = guiCfg.mainCfg; //update visible config on main window updateCompareButtons(); + updateFilterButton(m_bpButtonFilter, cfg.filterIsActive); //read folder pairs: @@ -1542,6 +1559,8 @@ bool MainDialog::readConfigurationFromXml(const wxString& filename, bool program ignoreErrors = guiCfg.ignoreErrors; + syncPreview->enablePreview(guiCfg.syncPreviewEnabled); + //########################################################### addFileToCfgHistory(filename); //put filename on list of last used config files @@ -1550,12 +1569,12 @@ bool MainDialog::readConfigurationFromXml(const wxString& filename, bool program if (filename == xmlAccess::LAST_CONFIG_FILE) //set title { SetTitle(wxString(wxT("FreeFileSync - ")) + _("Folder Comparison and Synchronization")); - proposedConfigFileName.clear(); + currentConfigFileName.clear(); } else { SetTitle(wxString(wxT("FreeFileSync - ")) + filename); - proposedConfigFileName = filename; + currentConfigFileName = filename; } return true; @@ -1585,12 +1604,12 @@ bool MainDialog::writeConfigurationToXml(const wxString& filename) if (filename == xmlAccess::LAST_CONFIG_FILE) //set title { SetTitle(wxString(wxT("FreeFileSync - ")) + _("Folder Comparison and Synchronization")); - proposedConfigFileName.clear(); + currentConfigFileName.clear(); } else { SetTitle(wxString(wxT("FreeFileSync - ")) + filename); - proposedConfigFileName = filename; + currentConfigFileName = filename; } return true; @@ -1610,6 +1629,8 @@ xmlAccess::XmlGuiConfig MainDialog::getCurrentConfiguration() const guiCfg.ignoreErrors = ignoreErrors; + guiCfg.syncPreviewEnabled = syncPreview->previewIsEnabled(); + return guiCfg; } @@ -1628,9 +1649,12 @@ void MainDialog::OnFilterButton(wxCommandEvent &event) updateFilterButton(m_bpButtonFilter, cfg.filterIsActive); if (cfg.filterIsActive) - FreeFileSync::filterGridData(currentGridData, cfg.includeFilter, cfg.excludeFilter); + { + FreeFileSync::FilterProcess filterInstance(cfg.includeFilter, cfg.excludeFilter); + filterInstance.filterGridData(currentGridData); + } else - FreeFileSync::includeAllRowsOnGrid(currentGridData); + FreeFileSync::FilterProcess::includeAllRowsOnGrid(currentGridData); updateGuiGrid(); } @@ -1653,24 +1677,26 @@ void MainDialog::OnHideFilteredButton(wxCommandEvent &event) void MainDialog::OnConfigureFilter(wxHyperlinkEvent &event) { - wxString beforeImage = cfg.includeFilter + wxChar(1) + cfg.excludeFilter; + const wxString beforeImage = cfg.includeFilter + wxChar(1) + cfg.excludeFilter; FilterDlg* filterDlg = new FilterDlg(this, cfg.includeFilter, cfg.excludeFilter); if (filterDlg->ShowModal() == FilterDlg::BUTTON_OKAY) { - wxString afterImage = cfg.includeFilter + wxChar(1) + cfg.excludeFilter; + const wxString afterImage = cfg.includeFilter + wxChar(1) + cfg.excludeFilter; if (beforeImage != afterImage) //if filter settings are changed: set filtering to "on" { if (afterImage == (wxString(wxT("*")) + wxChar(1))) //default { cfg.filterIsActive = false; - FreeFileSync::includeAllRowsOnGrid(currentGridData); + FreeFileSync::FilterProcess::includeAllRowsOnGrid(currentGridData); } else { cfg.filterIsActive = true; - FreeFileSync::filterGridData(currentGridData, cfg.includeFilter, cfg.excludeFilter); + + FreeFileSync::FilterProcess filterInstance(cfg.includeFilter, cfg.excludeFilter); + filterInstance.filterGridData(currentGridData); } updateFilterButton(m_bpButtonFilter, cfg.filterIsActive); @@ -1684,42 +1710,75 @@ void MainDialog::OnConfigureFilter(wxHyperlinkEvent &event) void MainDialog::OnLeftOnlyFiles(wxCommandEvent& event) { - leftOnlyFilesActive = !leftOnlyFilesActive; + gridDataView.leftOnlyFilesActive = !gridDataView.leftOnlyFilesActive; updateViewFilterButtons(); updateGuiGrid(); }; void MainDialog::OnLeftNewerFiles(wxCommandEvent& event) { - leftNewerFilesActive = !leftNewerFilesActive; + gridDataView.leftNewerFilesActive = !gridDataView.leftNewerFilesActive; updateViewFilterButtons(); updateGuiGrid(); }; void MainDialog::OnDifferentFiles(wxCommandEvent& event) { - differentFilesActive = !differentFilesActive; + gridDataView.differentFilesActive = !gridDataView.differentFilesActive; updateViewFilterButtons(); updateGuiGrid(); }; void MainDialog::OnRightNewerFiles(wxCommandEvent& event) { - rightNewerFilesActive = !rightNewerFilesActive; + gridDataView.rightNewerFilesActive = !gridDataView.rightNewerFilesActive; updateViewFilterButtons(); updateGuiGrid(); }; void MainDialog::OnRightOnlyFiles(wxCommandEvent& event) { - rightOnlyFilesActive = !rightOnlyFilesActive; + gridDataView.rightOnlyFilesActive = !gridDataView.rightOnlyFilesActive; updateViewFilterButtons(); updateGuiGrid(); }; + void MainDialog::OnEqualFiles(wxCommandEvent& event) { - equalFilesActive = !equalFilesActive; + gridDataView.equalFilesActive = !gridDataView.equalFilesActive; + updateViewFilterButtons(); + updateGuiGrid(); +}; + + +void MainDialog::OnConflictFiles(wxCommandEvent& event) +{ + gridDataView.conflictFilesActive = !gridDataView.conflictFilesActive; + updateViewFilterButtons(); + updateGuiGrid(); +}; + + +void MainDialog::OnSyncDirLeft(wxCommandEvent& event) +{ + gridDataView.syncDirLeftActive = !gridDataView.syncDirLeftActive; + updateViewFilterButtons(); + updateGuiGrid(); +}; + + +void MainDialog::OnSyncDirRight(wxCommandEvent& event) +{ + gridDataView.syncDirRightActive = !gridDataView.syncDirRightActive; + updateViewFilterButtons(); + updateGuiGrid(); +}; + + +void MainDialog::OnSyncDirNone(wxCommandEvent& event) +{ + gridDataView.syncDirNoneActive = !gridDataView.syncDirNoneActive; updateViewFilterButtons(); updateGuiGrid(); }; @@ -1727,7 +1786,8 @@ void MainDialog::OnEqualFiles(wxCommandEvent& event) void MainDialog::updateViewFilterButtons() { - if (leftOnlyFilesActive) + //compare result buttons + if (gridDataView.leftOnlyFilesActive) { m_bpButtonLeftOnly->SetBitmapLabel(*globalResource.bitmapLeftOnlyAct); m_bpButtonLeftOnly->SetToolTip(_("Hide files that exist on left side only")); @@ -1738,7 +1798,18 @@ void MainDialog::updateViewFilterButtons() m_bpButtonLeftOnly->SetToolTip(_("Show files that exist on left side only")); } - if (leftNewerFilesActive) + if (gridDataView.rightOnlyFilesActive) + { + m_bpButtonRightOnly->SetBitmapLabel(*globalResource.bitmapRightOnlyAct); + m_bpButtonRightOnly->SetToolTip(_("Hide files that exist on right side only")); + } + else + { + m_bpButtonRightOnly->SetBitmapLabel(*globalResource.bitmapRightOnlyDeact); + m_bpButtonRightOnly->SetToolTip(_("Show files that exist on right side only")); + } + + if (gridDataView.leftNewerFilesActive) { m_bpButtonLeftNewer->SetBitmapLabel(*globalResource.bitmapLeftNewerAct); m_bpButtonLeftNewer->SetToolTip(_("Hide files that are newer on left")); @@ -1749,7 +1820,18 @@ void MainDialog::updateViewFilterButtons() m_bpButtonLeftNewer->SetToolTip(_("Show files that are newer on left")); } - if (equalFilesActive) + if (gridDataView.rightNewerFilesActive) + { + m_bpButtonRightNewer->SetBitmapLabel(*globalResource.bitmapRightNewerAct); + m_bpButtonRightNewer->SetToolTip(_("Hide files that are newer on right")); + } + else + { + m_bpButtonRightNewer->SetBitmapLabel(*globalResource.bitmapRightNewerDeact); + m_bpButtonRightNewer->SetToolTip(_("Show files that are newer on right")); + } + + if (gridDataView.equalFilesActive) { m_bpButtonEqual->SetBitmapLabel(*globalResource.bitmapEqualAct); m_bpButtonEqual->SetToolTip(_("Hide files that are equal")); @@ -1760,7 +1842,7 @@ void MainDialog::updateViewFilterButtons() m_bpButtonEqual->SetToolTip(_("Show files that are equal")); } - if (differentFilesActive) + if (gridDataView.differentFilesActive) { m_bpButtonDifferent->SetBitmapLabel(*globalResource.bitmapDifferentAct); m_bpButtonDifferent->SetToolTip(_("Hide files that are different")); @@ -1771,26 +1853,49 @@ void MainDialog::updateViewFilterButtons() m_bpButtonDifferent->SetToolTip(_("Show files that are different")); } - if (rightNewerFilesActive) + if (gridDataView.conflictFilesActive) { - m_bpButtonRightNewer->SetBitmapLabel(*globalResource.bitmapRightNewerAct); - m_bpButtonRightNewer->SetToolTip(_("Hide files that are newer on right")); + m_bpButtonConflict->SetBitmapLabel(*globalResource.bitmapConflictAct); + m_bpButtonConflict->SetToolTip(_("Hide conflicts")); } else { - m_bpButtonRightNewer->SetBitmapLabel(*globalResource.bitmapRightNewerDeact); - m_bpButtonRightNewer->SetToolTip(_("Show files that are newer on right")); + m_bpButtonConflict->SetBitmapLabel(*globalResource.bitmapConflictDeact); + m_bpButtonConflict->SetToolTip(_("Show conflicts")); } - if (rightOnlyFilesActive) + //sync preview buttons + if (gridDataView.syncDirLeftActive) { - m_bpButtonRightOnly->SetBitmapLabel(*globalResource.bitmapRightOnlyAct); - m_bpButtonRightOnly->SetToolTip(_("Hide files that exist on right side only")); + m_bpButtonSyncDirLeft->SetBitmapLabel(*globalResource.bitmapSyncDirLeftAct); + m_bpButtonSyncDirLeft->SetToolTip(_("Hide files that will be copied to the left side")); } else { - m_bpButtonRightOnly->SetBitmapLabel(*globalResource.bitmapRightOnlyDeact); - m_bpButtonRightOnly->SetToolTip(_("Show files that exist on right side only")); + m_bpButtonSyncDirLeft->SetBitmapLabel(*globalResource.bitmapSyncDirLeftDeact); + m_bpButtonSyncDirLeft->SetToolTip(_("Show files that will be copied to the left side")); + } + + if (gridDataView.syncDirRightActive) + { + m_bpButtonSyncDirRight->SetBitmapLabel(*globalResource.bitmapSyncDirRightAct); + m_bpButtonSyncDirRight->SetToolTip(_("Hide files that will be copied to the right side")); + } + else + { + m_bpButtonSyncDirRight->SetBitmapLabel(*globalResource.bitmapSyncDirRightDeact); + m_bpButtonSyncDirRight->SetToolTip(_("Show files that will be copied to the right side")); + } + + if (gridDataView.syncDirNoneActive) + { + m_bpButtonSyncDirNone->SetBitmapLabel(*globalResource.bitmapSyncDirNoneAct); + m_bpButtonSyncDirNone->SetToolTip(_("Hide files that won't be copied")); + } + else + { + m_bpButtonSyncDirNone->SetBitmapLabel(*globalResource.bitmapSyncDirNoneDeact); + m_bpButtonSyncDirNone->SetToolTip(_("Show files that won't be copied")); } } @@ -1825,7 +1930,7 @@ void MainDialog::updateCompareButtons() } //disable the sync button - enableSynchronization(false); + syncPreview->enableSynchronization(false); //clear grids currentGridData.clear(); @@ -1867,13 +1972,22 @@ void MainDialog::OnCompare(wxCommandEvent &event) CompareStatusHandler statusHandler(this); cmpStatusHandlerTmp = &statusHandler; + //prepare filter + std::auto_ptr<FreeFileSync::FilterProcess> filterInstance(NULL); + if (cfg.filterIsActive) + filterInstance.reset(new FreeFileSync::FilterProcess(cfg.includeFilter, cfg.excludeFilter)); + + //begin comparison FreeFileSync::CompareProcess comparison(globalSettings.shared.traverseDirectorySymlinks, globalSettings.shared.fileTimeTolerance, + globalSettings.shared.ignoreOneHourDiff, globalSettings.shared.warningDependentFolders, + filterInstance.get(), &statusHandler); comparison.startCompareProcess(getFolderPairs(), cfg.compareVar, + cfg.syncConfiguration, currentGridData); //if (output.size < 50000) @@ -1881,26 +1995,22 @@ void MainDialog::OnCompare(wxCommandEvent &event) statusHandler.forceUiRefresh(); //keep total number of scanned files up to date gridDataView.sortView(GridView::SORT_BY_DIRECTORY, true, true); - - //filter currentGridData if option is set - if (cfg.filterIsActive) - FreeFileSync::filterGridData(currentGridData, cfg.includeFilter, cfg.excludeFilter); } catch (AbortThisProcess& theException) { aborted = true; } - cmpStatusHandlerTmp = 0; + cmpStatusHandlerTmp = NULL; if (aborted) { //disable the sync button - enableSynchronization(false); + syncPreview->enableSynchronization(false); m_buttonCompare->SetFocus(); } else { //once compare is finished enable the sync button - enableSynchronization(true); - m_buttonSync->SetFocus(); + syncPreview->enableSynchronization(true); + m_buttonStartSync->SetFocus(); //hide sort direction indicator on GUI grids m_gridLeft->setSortMarker(-1); @@ -1961,25 +2071,44 @@ void MainDialog::updateGuiGrid() m_gridRight->SetRowLabelSize(nrOfDigits * digitWidth + 4); } + //update sync preview statistics + calculatePreview(); + m_gridLeft->EndBatch(); m_gridMiddle->EndBatch(); m_gridRight->EndBatch(); } -void MainDialog::OnSync(wxCommandEvent& event) +void MainDialog::OnSwitchView(wxCommandEvent& event) +{ + //toggle view + syncPreview->enablePreview(!syncPreview->previewIsEnabled()); +} + + +void MainDialog::OnSyncSettings(wxCommandEvent& event) +{ + SyncDialog* syncDlg = new SyncDialog(this, currentGridData, cfg, ignoreErrors); + if (syncDlg->ShowModal() == SyncDialog::BUTTON_OKAY) + { + redetermineSyncDirection(cfg.syncConfiguration, currentGridData); + updateGuiGrid(); + } +} + + +void MainDialog::OnStartSync(wxCommandEvent& event) { - SyncDialog* syncDlg = new SyncDialog(this, currentGridData, cfg, ignoreErrors, synchronizationEnabled); - if (syncDlg->ShowModal() == SyncDialog::BUTTON_START) + if (syncPreview->synchronizationIsEnabled()) { //check if there are files/folders to be sync'ed at all - if (!synchronizationNeeded(currentGridData, cfg.syncConfiguration)) + if (!synchronizationNeeded(currentGridData)) { wxMessageBox(_("Nothing to synchronize according to configuration!"), _("Information"), wxICON_WARNING); return; } - wxBusyCursor dummy; //show hourglass cursor clearStatusBar(); @@ -1988,6 +2117,15 @@ void MainDialog::OnSync(wxCommandEvent& event) //class handling status updates and error messages SyncStatusHandler statusHandler(this, ignoreErrors); +// //small reminder that synchronization will be starting immediately +// if (globalSettings.shared.warningSynchronizationStarting) //test if check should be executed +// { +// bool dontShowAgain = false; +// statusHandler.reportWarning(_(""), +// dontShowAgain); +// globalSettings.shared.warningSynchronizationStarting = !dontShowAgain; +// } + //start synchronization and return elements that were not sync'ed in currentGridData FreeFileSync::SyncProcess synchronization( cfg.useRecycleBin, @@ -1995,9 +2133,10 @@ void MainDialog::OnSync(wxCommandEvent& event) globalSettings.shared.traverseDirectorySymlinks, globalSettings.shared.warningSignificantDifference, globalSettings.shared.warningNotEnoughDiskSpace, + globalSettings.shared.warningUnresolvedConflicts, &statusHandler); - synchronization.startSynchronizationProcess(currentGridData, cfg.syncConfiguration); + synchronization.startSynchronizationProcess(currentGridData); } catch (AbortThisProcess& theException) { //do NOT disable the sync button: user might want to try to sync the REMAINING rows @@ -2012,17 +2151,16 @@ void MainDialog::OnSync(wxCommandEvent& event) m_gridMiddle->ClearSelection(); m_gridRight->ClearSelection(); - if (gridDataView.elementsTotal() > 0) - pushStatusInformation(_("Not all items were synchronized! Have a look at the list.")); + if (!gridDataView.refGridIsEmpty()) + pushStatusInformation(_("Not all items have been synchronized! Have a look at the list.")); else { pushStatusInformation(_("All items have been synchronized!")); - enableSynchronization(false); + syncPreview->enableSynchronization(false); } } } - void MainDialog::OnLeftGridDoubleClick(wxGridEvent& event) { openWithFileManager(event.GetRow(), true); @@ -2056,7 +2194,7 @@ void MainDialog::OnSortLeftGrid(wxGridEvent& event) const xmlAccess::ColumnTypes columnType = m_gridLeft->getTypeAtPos(currentSortColumn); switch (columnType) { - case xmlAccess::FULL_NAME: + case xmlAccess::FULL_PATH: gridDataView.sortView(GridView::SORT_BY_DIRECTORY, true, sortAscending); break; case xmlAccess::FILENAME: @@ -2134,7 +2272,7 @@ void MainDialog::OnSortRightGrid(wxGridEvent& event) const xmlAccess::ColumnTypes columnType = m_gridRight->getTypeAtPos(currentSortColumn); switch (columnType) { - case xmlAccess::FULL_NAME: + case xmlAccess::FULL_PATH: gridDataView.sortView(GridView::SORT_BY_DIRECTORY, false, sortAscending); break; case xmlAccess::FILENAME: @@ -2167,7 +2305,7 @@ void MainDialog::OnSortRightGrid(wxGridEvent& event) } -void MainDialog::OnSwapDirs( wxCommandEvent& event ) +void MainDialog::OnSwapSides(wxCommandEvent& event) { //swap directory names: main pair const wxString leftDir = m_directoryLeft->GetValue(); @@ -2189,8 +2327,10 @@ void MainDialog::OnSwapDirs( wxCommandEvent& event ) } //swap view filter - std::swap(leftOnlyFilesActive, rightOnlyFilesActive); - std::swap(leftNewerFilesActive, rightNewerFilesActive); + std::swap(gridDataView.leftOnlyFilesActive, gridDataView.rightOnlyFilesActive); + std::swap(gridDataView.leftNewerFilesActive, gridDataView.rightNewerFilesActive); + std::swap(gridDataView.syncDirLeftActive, gridDataView.syncDirRightActive); + updateViewFilterButtons(); //swap grid information @@ -2202,16 +2342,11 @@ void MainDialog::OnSwapDirs( wxCommandEvent& event ) void MainDialog::updateGridViewData() { - const GridView::StatusInfo result = gridDataView.update( - leftOnlyFilesActive, - rightOnlyFilesActive, - leftNewerFilesActive, - rightNewerFilesActive, - differentFilesActive, - equalFilesActive, - hideFilteredElements); + const GridView::StatusInfo result = gridDataView.update(hideFilteredElements, syncPreview->previewIsEnabled()); //hide or enable view filter buttons + + //comparison result view buttons if (result.existsLeftOnly) m_bpButtonLeftOnly->Show(); else @@ -2242,12 +2377,38 @@ void MainDialog::updateGridViewData() else m_bpButtonEqual->Hide(); - if ( result.existsLeftOnly || - result.existsRightOnly || - result.existsLeftNewer || - result.existsRightNewer || - result.existsDifferent || - result.existsEqual) + if (result.existsConflict) + m_bpButtonConflict->Show(); + else + m_bpButtonConflict->Hide(); + + //sync preview buttons + if (result.existsSyncDirLeft) + m_bpButtonSyncDirLeft->Show(); + else + m_bpButtonSyncDirLeft->Hide(); + + if (result.existsSyncDirRight) + m_bpButtonSyncDirRight->Show(); + else + m_bpButtonSyncDirRight->Hide(); + + if (result.existsSyncDirNone) + m_bpButtonSyncDirNone->Show(); + else + m_bpButtonSyncDirNone->Hide(); + + + if ( result.existsLeftOnly || + result.existsRightOnly || + result.existsLeftNewer || + result.existsRightNewer || + result.existsDifferent || + result.existsEqual || + result.existsConflict || + result.existsSyncDirLeft || + result.existsSyncDirRight || + result.existsSyncDirNone) { m_panel112->Show(); m_panel112->Layout(); @@ -2304,8 +2465,7 @@ void MainDialog::updateGridViewData() } const wxString objectsView = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(gridDataView.elementsOnView())); - const unsigned int objCount = gridDataView.elementsTotal(); - if (objCount == 1) + if (result.objectsTotal == 1) { wxString outputString = _("%x of 1 row in view"); outputString.Replace(wxT("%x"), objectsView, false); @@ -2313,7 +2473,7 @@ void MainDialog::updateGridViewData() } else { - const wxString objectsTotal = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(objCount)); + const wxString objectsTotal = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(result.objectsTotal)); wxString outputString = _("%x of %y rows in view"); outputString.Replace(wxT("%x"), objectsView, false); @@ -2373,7 +2533,7 @@ void MainDialog::OnAddFolderPair(wxCommandEvent& event) addFolderPair(wxEmptyString, wxEmptyString); //disable the sync button - enableSynchronization(false); + syncPreview->enableSynchronization(false); //clear grids currentGridData.clear(); @@ -2392,7 +2552,7 @@ void MainDialog::OnRemoveFolderPair(wxCommandEvent& event) removeFolderPair(i - additionalFolderPairs.begin()); //disable the sync button - enableSynchronization(false); + syncPreview->enableSynchronization(false); //clear grids currentGridData.clear(); @@ -2403,6 +2563,33 @@ void MainDialog::OnRemoveFolderPair(wxCommandEvent& event) } +void MainDialog::calculatePreview() +{ + //update preview of bytes to be transferred: + int objectsToCreate = 0; + int objectsToOverwrite = 0; + int objectsToDelete = 0; + int conflictsDummy = 0; + wxULongLong dataToProcess; + FreeFileSync::calcTotalBytesToSync(currentGridData, + objectsToCreate, + objectsToOverwrite, + objectsToDelete, + conflictsDummy, + dataToProcess); + + const wxString toCreate = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(objectsToCreate)); + const wxString toUpdate = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(objectsToOverwrite)); + const wxString toDelete = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(objectsToDelete)); + const wxString data = FreeFileSync::formatFilesizeToShortString(dataToProcess); + + m_textCtrlCreate->SetValue(toCreate); + m_textCtrlUpdate->SetValue(toUpdate); + m_textCtrlDelete->SetValue(toDelete); + m_textCtrlData->SetValue(data); +} + + void MainDialog::addFolderPair(const Zstring& leftDir, const Zstring& rightDir) { std::vector<FolderPair> newPairs; @@ -2469,7 +2656,7 @@ void MainDialog::addFolderPair(const std::vector<FolderPair>& newPairs) m_scrolledWindowFolderPairs->Layout(); bSizer1->Layout(); - m_bpButtonSwap->Refresh(); + m_bpButtonSwitchView->Refresh(); } @@ -2637,10 +2824,9 @@ void MainDialog::OnMenuQuit(wxCommandEvent& event) requestShutdown(); } - //######################################################################################################### -//language selection +//language selection void MainDialog::switchProgramLanguage(const int langID) { programLanguage->setLanguage(langID); //language is a global attribute @@ -2734,4 +2920,90 @@ void MainDialog::OnMenuLangSpanish(wxCommandEvent& event) switchProgramLanguage(wxLANGUAGE_SPANISH); } +//######################################################################################################### + + +SyncPreview::SyncPreview(MainDialog* mainDlg) : + mainDlg_(mainDlg), + syncPreviewEnabled(false), + synchronizationEnabled(false) {} + + +bool SyncPreview::previewIsEnabled() +{ + return syncPreviewEnabled; +} + +void SyncPreview::enablePreview(bool value) +{ + if (value) + { + syncPreviewEnabled = true; + + mainDlg_->m_bpButtonSwitchView->SetBitmapLabel(*globalResource.bitmapSyncView); + mainDlg_->m_bpButtonSwitchView->SetToolTip(_("Synchronization Preview")); + + /*mainDlg_->m_bpButtonSyncConfig->Show(); + mainDlg_->m_bpButtonSyncConfig->Enable(); + + mainDlg_->m_buttonStartSync->Show(); + mainDlg_->m_buttonStartSync->Enable();*/ + + mainDlg_->m_panelSyncPreview->Show(); + + mainDlg_->bSizer6->Layout(); + + //toggle display of sync preview in middle grid + mainDlg_->m_gridMiddle->enableSyncPreview(true); + + mainDlg_->Refresh(); + } + else + { + syncPreviewEnabled = false; + + mainDlg_->m_bpButtonSwitchView->SetBitmapLabel(*globalResource.bitmapCmpView); + mainDlg_->m_bpButtonSwitchView->SetToolTip(_("Comparison Result")); + + /*mainDlg_->m_bpButtonSyncConfig->Disable(); + mainDlg_->m_bpButtonSyncConfig->Hide(); + + mainDlg_->m_buttonStartSync->Disable(); + mainDlg_->m_buttonStartSync->Hide();*/ + + mainDlg_->m_panelSyncPreview->Hide(); + + mainDlg_->bSizer6->Layout(); + + //toggle display of sync preview in middle grid + mainDlg_->m_gridMiddle->enableSyncPreview(false); + + mainDlg_->Refresh(); + } + + mainDlg_->updateGuiGrid(); +} + + +void SyncPreview::enableSynchronization(bool value) +{ + if (value) + { + synchronizationEnabled = true; + mainDlg_->m_buttonStartSync->SetForegroundColour(*wxBLACK); + mainDlg_->m_buttonStartSync->setBitmapFront(*globalResource.bitmapSync); + } + else + { + synchronizationEnabled = false; + mainDlg_->m_buttonStartSync->SetForegroundColour(wxColor(94, 94, 94)); //grey + mainDlg_->m_buttonStartSync->setBitmapFront(*globalResource.bitmapSyncDisabled); + } +} + + +bool SyncPreview::synchronizationIsEnabled() +{ + return synchronizationEnabled; +} diff --git a/ui/MainDialog.h b/ui/MainDialog.h index 49d5ceee..671da7ee 100644 --- a/ui/MainDialog.h +++ b/ui/MainDialog.h @@ -20,12 +20,16 @@ class CustomLocale; class MainFolderDragDrop; class FolderPairPanel; class CustomGrid; +class FFSCheckRowsEvent; +class FFSSyncDirectionEvent; +class SyncPreview; class MainDialog : public MainDialogGenerated { friend class CompareStatusHandler; friend class MainFolderDragDrop; + friend class SyncPreview; //IDs for context menu items enum //context menu for left and right grids @@ -36,6 +40,7 @@ class MainDialog : public MainDialogGenerated CONTEXT_CLIPBOARD, CONTEXT_EXPLORER, CONTEXT_DELETE_FILES, + CONTEXT_SWAP_SIDES }; enum //context menu for middle grid @@ -69,7 +74,7 @@ private: void writeGlobalSettings(); void updateViewFilterButtons(); - void updateFilterButton(wxBitmapButton* filterButton, bool isActive); + static void updateFilterButton(wxBitmapButton* filterButton, bool isActive); void updateCompareButtons(); void addFileToCfgHistory(const wxString& filename); @@ -87,8 +92,8 @@ private: void updateGridViewData(); //context menu functions - std::set<int> getSelectedRows(const CustomGrid* grid); - void filterRangeManually(const std::set<int>& rowsToFilterOnUiTable); + std::set<int> getSelectedRows(const CustomGrid* grid) const; + void filterRangeManually(const std::set<int>& rowsToFilterOnUiTable, const int leadingRow); void copySelectionToClipboard(const CustomGrid* selectedGrid); void openWithFileManager(const int rowNumber, const bool leftSide); void deleteSelectedFiles(); @@ -116,10 +121,8 @@ private: void requestShutdown(); //try to exit application - //manual filtering of rows: - void OnGridSelectCell(wxGridEvent& event); - void OnGrid3LeftMouseUp(wxEvent& event); - void OnGrid3LeftMouseDown(wxEvent& event); + void OnCheckRows(FFSCheckRowsEvent& event); + void OnSetSyncDirection(FFSSyncDirectionEvent& event); void OnLeftGridDoubleClick( wxGridEvent& event); void OnRightGridDoubleClick(wxGridEvent& event); @@ -128,15 +131,22 @@ private: void OnSortRightGrid( wxGridEvent& event); void OnLeftOnlyFiles( wxCommandEvent& event); + void OnRightOnlyFiles( wxCommandEvent& event); void OnLeftNewerFiles( wxCommandEvent& event); - void OnDifferentFiles( wxCommandEvent& event); void OnRightNewerFiles( wxCommandEvent& event); - void OnRightOnlyFiles( wxCommandEvent& event); void OnEqualFiles( wxCommandEvent& event); + void OnDifferentFiles( wxCommandEvent& event); + void OnConflictFiles( wxCommandEvent& event); + + void OnSyncDirLeft( wxCommandEvent& event); + void OnSyncDirRight( wxCommandEvent& event); + void OnSyncDirNone( wxCommandEvent& event); void OnSaveConfig( wxCommandEvent& event); void OnLoadConfig( wxCommandEvent& event); void OnLoadFromHistory( wxCommandEvent& event); + bool trySaveConfig(); //return true if saved successfully + void loadConfiguration(const wxString& filename); void OnCfgHistoryKeyEvent( wxKeyEvent& event); void OnFolderHistoryKeyEvent(wxKeyEvent& event); @@ -148,17 +158,21 @@ private: void OnHideFilteredButton( wxCommandEvent& event); void OnConfigureFilter( wxHyperlinkEvent& event); void OnShowHelpDialog( wxCommandEvent& event); - void OnSwapDirs( wxCommandEvent& event); + void OnSwapSides( wxCommandEvent& event); void OnCompareByTimeSize( wxCommandEvent& event); void OnCompareByContent( wxCommandEvent& event); void OnCompare( wxCommandEvent& event); - void OnSync( wxCommandEvent& event); + void OnSwitchView( wxCommandEvent& event); + void OnSyncSettings( wxCommandEvent& event); + void OnStartSync( wxCommandEvent& event); void OnClose( wxCloseEvent& event); void OnQuit( wxCommandEvent& event); void OnAddFolderPair( wxCommandEvent& event); void OnRemoveFolderPair( wxCommandEvent& event); + void calculatePreview(); + //menu events void OnMenuSaveConfig( wxCommandEvent& event); void OnMenuLoadConfig( wxCommandEvent& event); @@ -183,7 +197,6 @@ private: void OnMenuLangSpanish( wxCommandEvent& event); void switchProgramLanguage(const int langID); - void enableSynchronization(bool value); //*********************************************** //application variables are stored here: @@ -217,13 +230,6 @@ private: //convenience method to get all folder pairs (unformatted) std::vector<FreeFileSync::FolderPair> getFolderPairs() const; - //UI View Filter settings - bool leftOnlyFilesActive; - bool leftNewerFilesActive; - bool differentFilesActive; - bool equalFilesActive; - bool rightNewerFilesActive; - bool rightOnlyFilesActive; //*********************************************** std::auto_ptr<wxMenu> contextMenu; @@ -241,11 +247,7 @@ private: std::vector<wxString> cfgFileNames; //used when saving configuration - wxString proposedConfigFileName; - - //variables for filtering of m_grid3 - bool filteringInitialized; - bool filteringPending; + wxString currentConfigFileName; //temporal variables used by exclude via context menu wxString exFilterCandidateExtension; @@ -256,8 +258,6 @@ private: }; std::vector<FilterObject> exFilterCandidateObj; - bool synchronizationEnabled; //determines whether synchronization should be allowed - CompareStatusHandler* cmpStatusHandlerTmp; //used only by the abort button when comparing bool cleanedUp; //determines if destructor code was already executed @@ -269,6 +269,29 @@ private: //support for drag and drop std::auto_ptr<MainFolderDragDrop> dragDropOnLeft; std::auto_ptr<MainFolderDragDrop> dragDropOnRight; + + //encapsulation of handling of sync preview + std::auto_ptr<SyncPreview> syncPreview; +}; + + +class SyncPreview //encapsulates MainDialog functionality for synchronization preview (friend class) +{ + friend class MainDialog; + +public: + void enablePreview(bool value); + bool previewIsEnabled(); + + void enableSynchronization(bool value); + bool synchronizationIsEnabled(); + +private: + SyncPreview(MainDialog* mainDlg); + + MainDialog* mainDlg_; + bool syncPreviewEnabled; //toggle to display configuration preview instead of comparison result + bool synchronizationEnabled; //determines whether synchronization should be allowed }; #endif // MAINDIALOG_H diff --git a/ui/SmallDialogs.cpp b/ui/SmallDialogs.cpp index b553dff7..9ab09e88 100644 --- a/ui/SmallDialogs.cpp +++ b/ui/SmallDialogs.cpp @@ -80,7 +80,7 @@ HelpDlg::HelpDlg(wxWindow* window) : HelpDlgGenerated(window) m_treeCtrl1->AppendItem(treeDifferent, _("- left newer")); m_treeCtrl1->AppendItem(treeDifferent, _("- right newer")); - m_treeCtrl1->AppendItem(treeDifferent, _("- same date (different size)")); + m_treeCtrl1->AppendItem(treeDifferent, _("- conflict (same date, different size)")); m_treeCtrl1->ExpandAll(); @@ -451,9 +451,10 @@ void QuestionDlg::OnNo(wxCommandEvent& event) //######################################################################################## -CustomizeColsDlg::CustomizeColsDlg(wxWindow* window, xmlAccess::ColumnAttributes& attr) : +CustomizeColsDlg::CustomizeColsDlg(wxWindow* window, xmlAccess::ColumnAttributes& attr, bool& showFileIcons) : CustomizeColsDlgGenerated(window), - output(attr) + output(attr), + m_showFileIcons(showFileIcons) { m_bpButton29->SetBitmapLabel(*globalResource.bitmapMoveUp); m_bpButton30->SetBitmapLabel(*globalResource.bitmapMoveDown); @@ -468,6 +469,12 @@ CustomizeColsDlg::CustomizeColsDlg(wxWindow* window, xmlAccess::ColumnAttributes m_checkListColumns->Check(i - columnSettings.begin(), i->visible); } +#ifdef FFS_LINUX //file icons currently supported on Windows only + m_checkBoxShowFileIcons->Hide(); +#endif + + m_checkBoxShowFileIcons->SetValue(m_showFileIcons); + m_checkListColumns->SetSelection(0); Fit(); } @@ -489,6 +496,8 @@ void CustomizeColsDlg::OnOkay(wxCommandEvent& event) } } + m_showFileIcons = m_checkBoxShowFileIcons->GetValue(); + EndModal(BUTTON_OKAY); } @@ -503,6 +512,8 @@ void CustomizeColsDlg::OnDefault(wxCommandEvent& event) m_checkListColumns->Append(CustomGridRim::getTypeName(i->type)); m_checkListColumns->Check(i - defaultColumnAttr.begin(), i->visible); } + + m_checkBoxShowFileIcons->SetValue(true); } @@ -560,6 +571,8 @@ GlobalSettingsDlg::GlobalSettingsDlg(wxWindow* window, xmlAccess::XmlGlobalSetti m_buttonResetWarnings->setBitmapFront(*globalResource.bitmapWarningSmall, 5); m_spinCtrlFileTimeTolerance->SetValue(globalSettings.shared.fileTimeTolerance); + m_checkBoxIgnoreOneHour->SetValue(globalSettings.shared.ignoreOneHourDiff); + m_textCtrlFileManager->SetValue(globalSettings.gui.commandLineFileManager); Fit(); @@ -569,8 +582,9 @@ GlobalSettingsDlg::GlobalSettingsDlg(wxWindow* window, xmlAccess::XmlGlobalSetti void GlobalSettingsDlg::OnOkay(wxCommandEvent& event) { //write global settings only when okay-button is pressed! - settings.shared.fileTimeTolerance = m_spinCtrlFileTimeTolerance->GetValue(); + settings.shared.ignoreOneHourDiff = m_checkBoxIgnoreOneHour->GetValue(); + settings.gui.commandLineFileManager = m_textCtrlFileManager->GetValue(); EndModal(BUTTON_OKAY); @@ -588,6 +602,7 @@ void GlobalSettingsDlg::OnResetWarnings(wxCommandEvent& event) void GlobalSettingsDlg::OnDefault(wxCommandEvent& event) { m_spinCtrlFileTimeTolerance->SetValue(2); + m_checkBoxIgnoreOneHour->SetValue(true); #ifdef FFS_WIN m_textCtrlFileManager->SetValue(wxT("explorer /select, %name")); #elif defined FFS_LINUX @@ -948,13 +963,13 @@ void SyncStatus::setCurrentStatus(SyncStatusID id) break; case SCANNING: - m_bitmapStatus->SetBitmap(*globalResource.bitmapStatusComparing); + m_bitmapStatus->SetBitmap(*globalResource.bitmapStatusScanning); m_staticTextStatus->SetLabel(_("Scanning...")); break; - case COMPARING: - m_bitmapStatus->SetBitmap(*globalResource.bitmapStatusComparing); - m_staticTextStatus->SetLabel(_("Comparing...")); + case COMPARING_CONTENT: + m_bitmapStatus->SetBitmap(*globalResource.bitmapStatusBinCompare); + m_staticTextStatus->SetLabel(_("Comparing content...")); break; case SYNCHRONIZING: diff --git a/ui/SmallDialogs.h b/ui/SmallDialogs.h index a2d2c752..2c3e89d2 100644 --- a/ui/SmallDialogs.h +++ b/ui/SmallDialogs.h @@ -165,7 +165,7 @@ private: class CustomizeColsDlg : public CustomizeColsDlgGenerated { public: - CustomizeColsDlg(wxWindow* window, xmlAccess::ColumnAttributes& attr); + CustomizeColsDlg(wxWindow* window, xmlAccess::ColumnAttributes& attr, bool& showFileIcons); ~CustomizeColsDlg() {} enum @@ -183,6 +183,7 @@ private: void OnMoveDown(wxCommandEvent& event); xmlAccess::ColumnAttributes& output; + bool& m_showFileIcons; }; @@ -255,7 +256,7 @@ public: FINISHED_WITH_ERROR, PAUSE, SCANNING, - COMPARING, + COMPARING_CONTENT, SYNCHRONIZING }; diff --git a/ui/SyncDialog.cpp b/ui/SyncDialog.cpp index 3c684700..2004a06c 100644 --- a/ui/SyncDialog.cpp +++ b/ui/SyncDialog.cpp @@ -16,8 +16,7 @@ using namespace FreeFileSync; SyncDialog::SyncDialog(wxWindow* window, const FolderComparison& folderCmpRef, MainConfiguration& config, - bool& ignoreErrors, - bool synchronizationEnabled) : + bool& ignoreErrors) : SyncDlgGenerated(window), folderCmp(folderCmpRef), cfg(config), @@ -29,61 +28,43 @@ SyncDialog::SyncDialog(wxWindow* window, m_checkBoxIgnoreErrors->SetValue(m_ignoreErrors); //set sync config icons - updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration); - //update preview - calculatePreview(); + updateConfigIcons(cfg.compareVar, localSyncConfiguration); //set icons for this dialog - m_bitmap13->SetBitmap(*globalResource.bitmapLeftOnly); - m_bitmap14->SetBitmap(*globalResource.bitmapRightOnly); - m_bitmap15->SetBitmap(*globalResource.bitmapLeftNewer); - m_bitmap16->SetBitmap(*globalResource.bitmapRightNewer); - m_bitmap17->SetBitmap(*globalResource.bitmapDifferent); - - if (synchronizationEnabled) - { - m_button18->SetForegroundColour(*wxBLACK); - m_button18->setBitmapFront(*globalResource.bitmapStartSync); - m_button18->Enable(); - } - else - { - m_button18->SetForegroundColour(wxColor(94, 94, 94)); //grey - m_button18->setBitmapFront(*globalResource.bitmapStartSyncDis); - m_button18->Disable(); - m_button6->SetFocus(); - } + m_bitmapLeftOnly->SetBitmap(*globalResource.bitmapLeftOnly); + m_bitmapRightOnly->SetBitmap(*globalResource.bitmapRightOnly); + m_bitmapLeftNewer->SetBitmap(*globalResource.bitmapLeftNewer); + m_bitmapRightNewer->SetBitmap(*globalResource.bitmapRightNewer); + m_bitmapDifferent->SetBitmap(*globalResource.bitmapDifferent); bSizer201->Layout(); //wxButtonWithImage size might have changed - //set radiobutton - if ( localSyncConfiguration.exLeftSideOnly == SyncConfiguration::SYNC_DIR_RIGHT && - localSyncConfiguration.exRightSideOnly == SyncConfiguration::SYNC_DIR_RIGHT && - localSyncConfiguration.leftNewer == SyncConfiguration::SYNC_DIR_RIGHT && - localSyncConfiguration.rightNewer == SyncConfiguration::SYNC_DIR_RIGHT && - localSyncConfiguration.different == SyncConfiguration::SYNC_DIR_RIGHT) + if ( localSyncConfiguration.exLeftSideOnly == SYNC_DIR_RIGHT && + localSyncConfiguration.exRightSideOnly == SYNC_DIR_RIGHT && + localSyncConfiguration.leftNewer == SYNC_DIR_RIGHT && + localSyncConfiguration.rightNewer == SYNC_DIR_RIGHT && + localSyncConfiguration.different == SYNC_DIR_RIGHT) m_radioBtn1->SetValue(true); //one way -> - else if (localSyncConfiguration.exLeftSideOnly == SyncConfiguration::SYNC_DIR_RIGHT && - localSyncConfiguration.exRightSideOnly == SyncConfiguration::SYNC_DIR_NONE && - localSyncConfiguration.leftNewer == SyncConfiguration::SYNC_DIR_RIGHT && - localSyncConfiguration.rightNewer == SyncConfiguration::SYNC_DIR_NONE && - localSyncConfiguration.different == SyncConfiguration::SYNC_DIR_NONE) + else if (localSyncConfiguration.exLeftSideOnly == SYNC_DIR_RIGHT && + localSyncConfiguration.exRightSideOnly == SYNC_DIR_NONE && + localSyncConfiguration.leftNewer == SYNC_DIR_RIGHT && + localSyncConfiguration.rightNewer == SYNC_DIR_NONE && + localSyncConfiguration.different == SYNC_DIR_NONE) m_radioBtnUpdate->SetValue(true); //Update -> - else if (localSyncConfiguration.exLeftSideOnly == SyncConfiguration::SYNC_DIR_RIGHT && - localSyncConfiguration.exRightSideOnly == SyncConfiguration::SYNC_DIR_LEFT && - localSyncConfiguration.leftNewer == SyncConfiguration::SYNC_DIR_RIGHT && - localSyncConfiguration.rightNewer == SyncConfiguration::SYNC_DIR_LEFT && - localSyncConfiguration.different == SyncConfiguration::SYNC_DIR_NONE) + else if (localSyncConfiguration.exLeftSideOnly == SYNC_DIR_RIGHT && + localSyncConfiguration.exRightSideOnly == SYNC_DIR_LEFT && + localSyncConfiguration.leftNewer == SYNC_DIR_RIGHT && + localSyncConfiguration.rightNewer == SYNC_DIR_LEFT && + localSyncConfiguration.different == SYNC_DIR_NONE) m_radioBtn2->SetValue(true); //two way <-> else m_radioBtn3->SetValue(true); //other - //set tooltip for ambivalent category "different" - adjustToolTips(m_bitmap17, config.compareVar); + Fit(); } //################################################################################################################# @@ -91,136 +72,151 @@ SyncDialog::SyncDialog(wxWindow* window, SyncDialog::~SyncDialog() {} -void SyncDialog::updateConfigIcons(wxBitmapButton* button1, - wxBitmapButton* button2, - wxBitmapButton* button3, - wxBitmapButton* button4, - wxBitmapButton* button5, - const SyncConfiguration& syncConfig) +void SyncDialog::updateConfigIcons(const FreeFileSync::CompareVariant cmpVar, const FreeFileSync::SyncConfiguration& syncConfig) +{ + updateConfigIcons(cmpVar, + syncConfig, + m_bpButtonLeftOnly, + m_bpButtonRightOnly, + m_bpButtonLeftNewer, + m_bpButtonRightNewer, + m_bpButtonDifferent, + m_bitmapLeftOnly, + m_bitmapRightOnly, + m_bitmapLeftNewer, + m_bitmapRightNewer, + m_bitmapDifferent); +} + + +void SyncDialog::updateConfigIcons(const CompareVariant compareVar, + const SyncConfiguration& syncConfig, + wxBitmapButton* buttonLeftOnly, + wxBitmapButton* buttonRightOnly, + wxBitmapButton* buttonLeftNewer, + wxBitmapButton* buttonRightNewer, + wxBitmapButton* buttonDifferent, + wxStaticBitmap* bitmapLeftOnly, + wxStaticBitmap* bitmapRightOnly, + wxStaticBitmap* bitmapLeftNewer, + wxStaticBitmap* bitmapRightNewer, + wxStaticBitmap* bitmapDifferent) { - if (syncConfig.exLeftSideOnly == SyncConfiguration::SYNC_DIR_RIGHT) + //display only relevant sync options + switch (compareVar) { - button1->SetBitmapLabel(*globalResource.bitmapArrowRightCr); - button1->SetToolTip(_("Copy from left to right")); + case CMP_BY_TIME_SIZE: + buttonLeftOnly->Show(); + buttonRightOnly->Show(); + buttonLeftNewer->Show(); + buttonRightNewer->Show(); + buttonDifferent->Hide(); + + bitmapLeftOnly->Show(); + bitmapRightOnly->Show(); + bitmapLeftNewer->Show(); + bitmapRightNewer->Show(); + bitmapDifferent->Hide(); + break; + + case CMP_BY_CONTENT: + buttonLeftOnly->Show(); + buttonRightOnly->Show(); + buttonLeftNewer->Hide(); + buttonRightNewer->Hide(); + buttonDifferent->Show(); + + bitmapLeftOnly->Show(); + bitmapRightOnly->Show(); + bitmapLeftNewer->Hide(); + bitmapRightNewer->Hide(); + bitmapDifferent->Show(); + break; } - else if (syncConfig.exLeftSideOnly == SyncConfiguration::SYNC_DIR_LEFT) + + + if (syncConfig.exLeftSideOnly == SYNC_DIR_RIGHT) + { + buttonLeftOnly->SetBitmapLabel(*globalResource.bitmapArrowRightCr); + buttonLeftOnly->SetToolTip(_("Copy from left to right")); + } + else if (syncConfig.exLeftSideOnly == SYNC_DIR_LEFT) { - button1->SetBitmapLabel(*globalResource.bitmapDeleteLeft); - button1->SetToolTip(_("Delete files/folders existing on left side only")); + buttonLeftOnly->SetBitmapLabel(*globalResource.bitmapDeleteLeft); + buttonLeftOnly->SetToolTip(_("Delete files/folders existing on left side only")); } - else if (syncConfig.exLeftSideOnly == SyncConfiguration::SYNC_DIR_NONE) + else if (syncConfig.exLeftSideOnly == SYNC_DIR_NONE) { - button1->SetBitmapLabel(*globalResource.bitmapArrowNone); - button1->SetToolTip(_("Do nothing")); + buttonLeftOnly->SetBitmapLabel(*globalResource.bitmapArrowNone); + buttonLeftOnly->SetToolTip(_("Do nothing")); } - if (syncConfig.exRightSideOnly == SyncConfiguration::SYNC_DIR_RIGHT) + if (syncConfig.exRightSideOnly == SYNC_DIR_RIGHT) { - button2->SetBitmapLabel(*globalResource.bitmapDeleteRight); - button2->SetToolTip(_("Delete files/folders existing on right side only")); + buttonRightOnly->SetBitmapLabel(*globalResource.bitmapDeleteRight); + buttonRightOnly->SetToolTip(_("Delete files/folders existing on right side only")); } - else if (syncConfig.exRightSideOnly == SyncConfiguration::SYNC_DIR_LEFT) + else if (syncConfig.exRightSideOnly == SYNC_DIR_LEFT) { - button2->SetBitmapLabel(*globalResource.bitmapArrowLeftCr); - button2->SetToolTip(_("Copy from right to left")); + buttonRightOnly->SetBitmapLabel(*globalResource.bitmapArrowLeftCr); + buttonRightOnly->SetToolTip(_("Copy from right to left")); } - else if (syncConfig.exRightSideOnly == SyncConfiguration::SYNC_DIR_NONE) + else if (syncConfig.exRightSideOnly == SYNC_DIR_NONE) { - button2->SetBitmapLabel(*globalResource.bitmapArrowNone); - button2->SetToolTip(_("Do nothing")); + buttonRightOnly->SetBitmapLabel(*globalResource.bitmapArrowNone); + buttonRightOnly->SetToolTip(_("Do nothing")); } - if (syncConfig.leftNewer == SyncConfiguration::SYNC_DIR_RIGHT) + if (syncConfig.leftNewer == SYNC_DIR_RIGHT) { - button3->SetBitmapLabel(*globalResource.bitmapArrowRight); - button3->SetToolTip(_("Copy from left to right overwriting")); + buttonLeftNewer->SetBitmapLabel(*globalResource.bitmapArrowRight); + buttonLeftNewer->SetToolTip(_("Copy from left to right overwriting")); } - else if (syncConfig.leftNewer == SyncConfiguration::SYNC_DIR_LEFT) + else if (syncConfig.leftNewer == SYNC_DIR_LEFT) { - button3->SetBitmapLabel(*globalResource.bitmapArrowLeft); - button3->SetToolTip(_("Copy from right to left overwriting")); + buttonLeftNewer->SetBitmapLabel(*globalResource.bitmapArrowLeft); + buttonLeftNewer->SetToolTip(_("Copy from right to left overwriting")); } - else if (syncConfig.leftNewer == SyncConfiguration::SYNC_DIR_NONE) + else if (syncConfig.leftNewer == SYNC_DIR_NONE) { - button3->SetBitmapLabel(*globalResource.bitmapArrowNone); - button3->SetToolTip(_("Do nothing")); + buttonLeftNewer->SetBitmapLabel(*globalResource.bitmapArrowNone); + buttonLeftNewer->SetToolTip(_("Do nothing")); } - if (syncConfig.rightNewer == SyncConfiguration::SYNC_DIR_RIGHT) + if (syncConfig.rightNewer == SYNC_DIR_RIGHT) { - button4->SetBitmapLabel(*globalResource.bitmapArrowRight); - button4->SetToolTip(_("Copy from left to right overwriting")); + buttonRightNewer->SetBitmapLabel(*globalResource.bitmapArrowRight); + buttonRightNewer->SetToolTip(_("Copy from left to right overwriting")); } - else if (syncConfig.rightNewer == SyncConfiguration::SYNC_DIR_LEFT) + else if (syncConfig.rightNewer == SYNC_DIR_LEFT) { - button4->SetBitmapLabel(*globalResource.bitmapArrowLeft); - button4->SetToolTip(_("Copy from right to left overwriting")); + buttonRightNewer->SetBitmapLabel(*globalResource.bitmapArrowLeft); + buttonRightNewer->SetToolTip(_("Copy from right to left overwriting")); } - else if (syncConfig.rightNewer == SyncConfiguration::SYNC_DIR_NONE) + else if (syncConfig.rightNewer == SYNC_DIR_NONE) { - button4->SetBitmapLabel(*globalResource.bitmapArrowNone); - button4->SetToolTip(_("Do nothing")); + buttonRightNewer->SetBitmapLabel(*globalResource.bitmapArrowNone); + buttonRightNewer->SetToolTip(_("Do nothing")); } - if (syncConfig.different == SyncConfiguration::SYNC_DIR_RIGHT) + if (syncConfig.different == SYNC_DIR_RIGHT) { - button5->SetBitmapLabel(*globalResource.bitmapArrowRight); - button5->SetToolTip(_("Copy from left to right overwriting")); + buttonDifferent->SetBitmapLabel(*globalResource.bitmapArrowRight); + buttonDifferent->SetToolTip(_("Copy from left to right overwriting")); } - else if (syncConfig.different == SyncConfiguration::SYNC_DIR_LEFT) + else if (syncConfig.different == SYNC_DIR_LEFT) { - button5->SetBitmapLabel(*globalResource.bitmapArrowLeft); - button5->SetToolTip(_("Copy from right to left overwriting")); + buttonDifferent->SetBitmapLabel(*globalResource.bitmapArrowLeft); + buttonDifferent->SetToolTip(_("Copy from right to left overwriting")); } - else if (syncConfig.different == SyncConfiguration::SYNC_DIR_NONE) + else if (syncConfig.different == SYNC_DIR_NONE) { - button5->SetBitmapLabel(*globalResource.bitmapArrowNone); - button5->SetToolTip(_("Do nothing")); + buttonDifferent->SetBitmapLabel(*globalResource.bitmapArrowNone); + buttonDifferent->SetToolTip(_("Do nothing")); } } -void SyncDialog::adjustToolTips(wxStaticBitmap* bitmap, const CompareVariant var) -{ - //set tooltip for ambivalent category "different" - switch (var) - { - case CMP_BY_TIME_SIZE: - bitmap->SetToolTip(_("Files that exist on both sides, have same date but different filesizes")); - break; - case CMP_BY_CONTENT: - bitmap->SetToolTip(_("Files that exist on both sides and have different content")); - break; - } -} - - -void SyncDialog::calculatePreview() -{ - //update preview of bytes to be transferred: - int objectsToCreate = 0; - int objectsToOverwrite = 0; - int objectsToDelete = 0; - wxULongLong dataToProcess; - FreeFileSync::calcTotalBytesToSync(folderCmp, - localSyncConfiguration, - objectsToCreate, - objectsToOverwrite, - objectsToDelete, - dataToProcess); - - const wxString toCreate = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(objectsToCreate)); - const wxString toUpdate = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(objectsToOverwrite)); - const wxString toDelete = globalFunctions::includeNumberSeparator(globalFunctions::numberToWxString(objectsToDelete)); - const wxString data = FreeFileSync::formatFilesizeToShortString(dataToProcess); - - m_textCtrlCreate->SetValue(toCreate); - m_textCtrlUpdate->SetValue(toUpdate); - m_textCtrlDelete->SetValue(toDelete); - m_textCtrlData->SetValue(data); -} - - void SyncDialog::OnClose(wxCloseEvent& event) { EndModal(0); @@ -233,24 +229,14 @@ void SyncDialog::OnCancel(wxCommandEvent& event) } -void SyncDialog::OnBack(wxCommandEvent& event) -{ - //write configuration to main dialog - cfg.syncConfiguration = localSyncConfiguration; - cfg.useRecycleBin = m_checkBoxUseRecycler->GetValue(); - m_ignoreErrors = m_checkBoxIgnoreErrors->GetValue(); - - EndModal(0); -} - -void SyncDialog::OnStartSync(wxCommandEvent& event) +void SyncDialog::OnApply(wxCommandEvent& event) { //write configuration to main dialog cfg.syncConfiguration = localSyncConfiguration; cfg.useRecycleBin = m_checkBoxUseRecycler->GetValue(); m_ignoreErrors = m_checkBoxIgnoreErrors->GetValue(); - EndModal(BUTTON_START); + EndModal(BUTTON_OKAY); } @@ -269,14 +255,13 @@ void SyncDialog::OnSelectRecycleBin(wxCommandEvent& event) void SyncDialog::OnSyncLeftToRight(wxCommandEvent& event) { - localSyncConfiguration.exLeftSideOnly = SyncConfiguration::SYNC_DIR_RIGHT; - localSyncConfiguration.exRightSideOnly = SyncConfiguration::SYNC_DIR_RIGHT; - localSyncConfiguration.leftNewer = SyncConfiguration::SYNC_DIR_RIGHT; - localSyncConfiguration.rightNewer = SyncConfiguration::SYNC_DIR_RIGHT; - localSyncConfiguration.different = SyncConfiguration::SYNC_DIR_RIGHT; + localSyncConfiguration.exLeftSideOnly = SYNC_DIR_RIGHT; + localSyncConfiguration.exRightSideOnly = SYNC_DIR_RIGHT; + localSyncConfiguration.leftNewer = SYNC_DIR_RIGHT; + localSyncConfiguration.rightNewer = SYNC_DIR_RIGHT; + localSyncConfiguration.different = SYNC_DIR_RIGHT; - updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration); - calculatePreview(); + updateConfigIcons(cfg.compareVar, localSyncConfiguration); //if event is triggered by button m_radioBtn1->SetValue(true); @@ -285,14 +270,13 @@ void SyncDialog::OnSyncLeftToRight(wxCommandEvent& event) void SyncDialog::OnSyncUpdate(wxCommandEvent& event) { - localSyncConfiguration.exLeftSideOnly = SyncConfiguration::SYNC_DIR_RIGHT; - localSyncConfiguration.exRightSideOnly = SyncConfiguration::SYNC_DIR_NONE; - localSyncConfiguration.leftNewer = SyncConfiguration::SYNC_DIR_RIGHT; - localSyncConfiguration.rightNewer = SyncConfiguration::SYNC_DIR_NONE; - localSyncConfiguration.different = SyncConfiguration::SYNC_DIR_NONE; + localSyncConfiguration.exLeftSideOnly = SYNC_DIR_RIGHT; + localSyncConfiguration.exRightSideOnly = SYNC_DIR_NONE; + localSyncConfiguration.leftNewer = SYNC_DIR_RIGHT; + localSyncConfiguration.rightNewer = SYNC_DIR_NONE; + localSyncConfiguration.different = SYNC_DIR_NONE; - updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration); - calculatePreview(); + updateConfigIcons(cfg.compareVar, localSyncConfiguration); //if event is triggered by button m_radioBtnUpdate->SetValue(true); @@ -301,28 +285,27 @@ void SyncDialog::OnSyncUpdate(wxCommandEvent& event) void SyncDialog::OnSyncBothSides(wxCommandEvent& event) { - localSyncConfiguration.exLeftSideOnly = SyncConfiguration::SYNC_DIR_RIGHT; - localSyncConfiguration.exRightSideOnly = SyncConfiguration::SYNC_DIR_LEFT; - localSyncConfiguration.leftNewer = SyncConfiguration::SYNC_DIR_RIGHT; - localSyncConfiguration.rightNewer = SyncConfiguration::SYNC_DIR_LEFT; - localSyncConfiguration.different = SyncConfiguration::SYNC_DIR_NONE; + localSyncConfiguration.exLeftSideOnly = SYNC_DIR_RIGHT; + localSyncConfiguration.exRightSideOnly = SYNC_DIR_LEFT; + localSyncConfiguration.leftNewer = SYNC_DIR_RIGHT; + localSyncConfiguration.rightNewer = SYNC_DIR_LEFT; + localSyncConfiguration.different = SYNC_DIR_NONE; - updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration); - calculatePreview(); + updateConfigIcons(cfg.compareVar, localSyncConfiguration); //if event is triggered by button m_radioBtn2->SetValue(true); } -void toggleSyncDirection(SyncConfiguration::Direction& current) +void toggleSyncDirection(SyncDirection& current) { - if (current == SyncConfiguration::SYNC_DIR_RIGHT) - current = SyncConfiguration::SYNC_DIR_LEFT; - else if (current == SyncConfiguration::SYNC_DIR_LEFT) - current = SyncConfiguration::SYNC_DIR_NONE; - else if (current== SyncConfiguration::SYNC_DIR_NONE) - current = SyncConfiguration::SYNC_DIR_RIGHT; + if (current == SYNC_DIR_RIGHT) + current = SYNC_DIR_LEFT; + else if (current == SYNC_DIR_LEFT) + current = SYNC_DIR_NONE; + else if (current== SYNC_DIR_NONE) + current = SYNC_DIR_RIGHT; else assert (false); } @@ -331,8 +314,7 @@ void toggleSyncDirection(SyncConfiguration::Direction& current) void SyncDialog::OnExLeftSideOnly( wxCommandEvent& event ) { toggleSyncDirection(localSyncConfiguration.exLeftSideOnly); - updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration); - calculatePreview(); + updateConfigIcons(cfg.compareVar, localSyncConfiguration); //set custom config button m_radioBtn3->SetValue(true); } @@ -341,8 +323,7 @@ void SyncDialog::OnExLeftSideOnly( wxCommandEvent& event ) void SyncDialog::OnExRightSideOnly( wxCommandEvent& event ) { toggleSyncDirection(localSyncConfiguration.exRightSideOnly); - updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration); - calculatePreview(); + updateConfigIcons(cfg.compareVar, localSyncConfiguration); //set custom config button m_radioBtn3->SetValue(true); } @@ -351,8 +332,7 @@ void SyncDialog::OnExRightSideOnly( wxCommandEvent& event ) void SyncDialog::OnLeftNewer( wxCommandEvent& event ) { toggleSyncDirection(localSyncConfiguration.leftNewer); - updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration); - calculatePreview(); + updateConfigIcons(cfg.compareVar, localSyncConfiguration); //set custom config button m_radioBtn3->SetValue(true); } @@ -361,8 +341,7 @@ void SyncDialog::OnLeftNewer( wxCommandEvent& event ) void SyncDialog::OnRightNewer( wxCommandEvent& event ) { toggleSyncDirection(localSyncConfiguration.rightNewer); - updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration); - calculatePreview(); + updateConfigIcons(cfg.compareVar, localSyncConfiguration); //set custom config button m_radioBtn3->SetValue(true); } @@ -371,8 +350,7 @@ void SyncDialog::OnRightNewer( wxCommandEvent& event ) void SyncDialog::OnDifferent( wxCommandEvent& event ) { toggleSyncDirection(localSyncConfiguration.different); - updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration); - calculatePreview(); + updateConfigIcons(cfg.compareVar, localSyncConfiguration); //set custom config button m_radioBtn3->SetValue(true); } @@ -452,11 +430,11 @@ void BatchDialog::init() dragDropOnLogfileDir.reset(new DragDropOnDlg(m_panelLogging, m_dirPickerLogfileDir, m_textCtrlLogfileDir)); //set icons for this dialog - m_bitmap13->SetBitmap(*globalResource.bitmapLeftOnly); - m_bitmap14->SetBitmap(*globalResource.bitmapRightOnly); - m_bitmap15->SetBitmap(*globalResource.bitmapLeftNewer); - m_bitmap16->SetBitmap(*globalResource.bitmapRightNewer); - m_bitmap17->SetBitmap(*globalResource.bitmapDifferent); + m_bitmapLeftOnly->SetBitmap(*globalResource.bitmapLeftOnly); + m_bitmapRightOnly->SetBitmap(*globalResource.bitmapRightOnly); + m_bitmapLeftNewer->SetBitmap(*globalResource.bitmapLeftNewer); + m_bitmapRightNewer->SetBitmap(*globalResource.bitmapRightNewer); + m_bitmapDifferent->SetBitmap(*globalResource.bitmapDifferent); m_bitmap8->SetBitmap(*globalResource.bitmapInclude); m_bitmap9->SetBitmap(*globalResource.bitmapExclude); m_bitmap27->SetBitmap(*globalResource.bitmapBatch); @@ -536,35 +514,35 @@ void BatchDialog::OnChangeErrorHandling(wxCommandEvent& event) void BatchDialog::OnExLeftSideOnly(wxCommandEvent& event) { toggleSyncDirection(localSyncConfiguration.exLeftSideOnly); - SyncDialog::updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration); + updateConfigIcons(getCurrentCompareVar(), localSyncConfiguration); } void BatchDialog::OnExRightSideOnly(wxCommandEvent& event) { toggleSyncDirection(localSyncConfiguration.exRightSideOnly); - SyncDialog::updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration); + updateConfigIcons(getCurrentCompareVar(), localSyncConfiguration); } void BatchDialog::OnLeftNewer(wxCommandEvent& event) { toggleSyncDirection(localSyncConfiguration.leftNewer); - SyncDialog::updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration); + updateConfigIcons(getCurrentCompareVar(), localSyncConfiguration); } void BatchDialog::OnRightNewer(wxCommandEvent& event) { toggleSyncDirection(localSyncConfiguration.rightNewer); - SyncDialog::updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration); + updateConfigIcons(getCurrentCompareVar(), localSyncConfiguration); } void BatchDialog::OnDifferent(wxCommandEvent& event) { toggleSyncDirection(localSyncConfiguration.different); - SyncDialog::updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration); + updateConfigIcons(getCurrentCompareVar(), localSyncConfiguration); } @@ -630,21 +608,41 @@ void BatchDialog::OnSelectRecycleBin(wxCommandEvent& event) } -void BatchDialog::OnChangeCompareVar(wxCommandEvent& event) +CompareVariant BatchDialog::getCurrentCompareVar() { - CompareVariant var; if (m_radioBtnSizeDate->GetValue()) - var = CMP_BY_TIME_SIZE; + return CMP_BY_TIME_SIZE; else if (m_radioBtnContent->GetValue()) - var = CMP_BY_CONTENT; + return CMP_BY_CONTENT; else { assert(false); - var = CMP_BY_TIME_SIZE; + return CMP_BY_TIME_SIZE; } +} - //set tooltip for ambivalent category "different" - SyncDialog::adjustToolTips(m_bitmap17, var); + +void BatchDialog::updateConfigIcons(const FreeFileSync::CompareVariant cmpVar, const FreeFileSync::SyncConfiguration& syncConfig) +{ + SyncDialog::updateConfigIcons(cmpVar, + syncConfig, + m_bpButtonLeftOnly, + m_bpButtonRightOnly, + m_bpButtonLeftNewer, + m_bpButtonRightNewer, + m_bpButtonDifferent, + m_bitmapLeftOnly, + m_bitmapRightOnly, + m_bitmapLeftNewer, + m_bitmapRightNewer, + m_bitmapDifferent); +} + + +void BatchDialog::OnChangeCompareVar(wxCommandEvent& event) +{ + updateConfigIcons(getCurrentCompareVar(), localSyncConfiguration); + Fit(); } @@ -700,13 +698,7 @@ bool BatchDialog::saveBatchFile(const wxString& filename) xmlAccess::XmlBatchConfig batchCfg; //load structure with basic settings "mainCfg" - if (m_radioBtnSizeDate->GetValue()) - batchCfg.mainCfg.compareVar = CMP_BY_TIME_SIZE; - else if (m_radioBtnContent->GetValue()) - batchCfg.mainCfg.compareVar = CMP_BY_CONTENT; - else - return false; - + batchCfg.mainCfg.compareVar = getCurrentCompareVar(); batchCfg.mainCfg.syncConfiguration = localSyncConfiguration; batchCfg.mainCfg.filterIsActive = m_checkBoxFilter->GetValue(); batchCfg.mainCfg.includeFilter = m_textCtrlInclude->GetValue(); @@ -770,7 +762,6 @@ void BatchDialog::loadBatchCfg(const xmlAccess::XmlBatchConfig& batchCfg) { //make working copy of mainDialog.cfg.syncConfiguration and recycler setting localSyncConfiguration = batchCfg.mainCfg.syncConfiguration; - SyncDialog::updateConfigIcons(m_bpButton5, m_bpButton6, m_bpButton7, m_bpButton8, m_bpButton9, localSyncConfiguration); m_checkBoxUseRecycler->SetValue(batchCfg.mainCfg.useRecycleBin); setSelectionHandleError(batchCfg.handleError); @@ -783,11 +774,9 @@ void BatchDialog::loadBatchCfg(const xmlAccess::XmlBatchConfig& batchCfg) case CMP_BY_CONTENT: m_radioBtnContent->SetValue(true); break; - default: - assert (false); } - //adjust toolTip - SyncDialog::adjustToolTips(m_bitmap17, batchCfg.mainCfg.compareVar); + + updateConfigIcons(batchCfg.mainCfg.compareVar, batchCfg.mainCfg.syncConfiguration); m_checkBoxFilter->SetValue(batchCfg.mainCfg.filterIsActive); m_textCtrlInclude->SetValue(batchCfg.mainCfg.includeFilter); diff --git a/ui/SyncDialog.h b/ui/SyncDialog.h index 2c705122..940efac7 100644 --- a/ui/SyncDialog.h +++ b/ui/SyncDialog.h @@ -21,28 +21,31 @@ public: SyncDialog(wxWindow* window, const FreeFileSync::FolderComparison& folderCmpRef, FreeFileSync::MainConfiguration& config, - bool& ignoreErrors, - bool synchronizationEnabled); + bool& ignoreErrors); ~SyncDialog(); enum { - BUTTON_START = 15 + BUTTON_OKAY = 10 }; - static void updateConfigIcons(wxBitmapButton* button1, - wxBitmapButton* button2, - wxBitmapButton* button3, - wxBitmapButton* button4, - wxBitmapButton* button5, - const FreeFileSync::SyncConfiguration& syncConfig); - - static void adjustToolTips(wxStaticBitmap* bitmap, const FreeFileSync::CompareVariant var); + static void updateConfigIcons(const FreeFileSync::CompareVariant compareVar, + const FreeFileSync::SyncConfiguration& syncConfig, + wxBitmapButton* buttonLeftOnly, + wxBitmapButton* buttonRightOnly, + wxBitmapButton* buttonLeftNewer, + wxBitmapButton* buttonRightNewer, + wxBitmapButton* buttonDifferent, + wxStaticBitmap* bitmapLeftOnly, + wxStaticBitmap* bitmapRightOnly, + wxStaticBitmap* bitmapLeftNewer, + wxStaticBitmap* bitmapRightNewer, + wxStaticBitmap* bitmapDifferent); + //some syntax relaxation + void updateConfigIcons(const FreeFileSync::CompareVariant cmpVar, const FreeFileSync::SyncConfiguration& syncConfig); private: - void calculatePreview(); - void OnSyncLeftToRight( wxCommandEvent& event); void OnSyncUpdate( wxCommandEvent& event); void OnSyncBothSides( wxCommandEvent& event); @@ -53,10 +56,9 @@ private: void OnRightNewer( wxCommandEvent& event); void OnDifferent( wxCommandEvent& event); - void OnStartSync( wxCommandEvent& event); void OnClose( wxCloseEvent& event); - void OnBack( wxCommandEvent& event); void OnCancel( wxCommandEvent& event); + void OnApply( wxCommandEvent& event); void OnSelectRecycleBin(wxCommandEvent& event); @@ -98,6 +100,11 @@ private: void OnSelectRecycleBin(wxCommandEvent& event); void OnChangeCompareVar(wxCommandEvent& event); + FreeFileSync::CompareVariant getCurrentCompareVar(); + + void updateConfigIcons(const FreeFileSync::CompareVariant cmpVar, const FreeFileSync::SyncConfiguration& syncConfig); + + void updateVisibleTabs(); void showNotebookpage(wxWindow* page, const wxString& pageName, bool show); diff --git a/ui/batchStatusHandler.cpp b/ui/batchStatusHandler.cpp index 462b1921..716dccd5 100644 --- a/ui/batchStatusHandler.cpp +++ b/ui/batchStatusHandler.cpp @@ -209,7 +209,7 @@ BatchStatusHandlerSilent::~BatchStatusHandlerSilent() unsigned int failedItems = unhandledErrors.GetCount(); //write result - if (abortRequested) + if (abortIsRequested()) { returnValue = -4; m_log->write(_("Synchronization aborted!"), _("Error")); @@ -227,8 +227,18 @@ BatchStatusHandlerSilent::~BatchStatusHandlerSilent() inline void BatchStatusHandlerSilent::updateStatusText(const Zstring& text) { - if (currentProcess == StatusHandler::PROCESS_SYNCHRONIZING) + switch (currentProcess) + { + case StatusHandler::PROCESS_SCANNING: + case StatusHandler::PROCESS_COMPARING_CONTENT: + break; + case StatusHandler::PROCESS_SYNCHRONIZING: m_log->write(text.c_str(), _("Info")); + break; + case StatusHandler::PROCESS_NONE: + assert(false); + break; + } } @@ -360,7 +370,7 @@ void BatchStatusHandlerSilent::reportWarning(const Zstring& warningMessage, bool void BatchStatusHandlerSilent::addFinalInfo(const Zstring& infoMessage) { - m_log->write(infoMessage.c_str(), _("Info")); + m_log->write(infoMessage.c_str(), _("Info")); } @@ -372,7 +382,7 @@ void BatchStatusHandlerSilent::forceUiRefresh() void BatchStatusHandlerSilent::abortThisProcess() //used by sys-tray menu { - abortRequested = true; + requestAbortion(); throw FreeFileSync::AbortThisProcess(); } @@ -416,7 +426,7 @@ BatchStatusHandlerGui::~BatchStatusHandlerGui() finalMessage += finalInfo + wxT("\n\n"); //notify to syncStatusFrame that current process has ended - if (abortRequested) + if (abortIsRequested()) { returnValue = -4; finalMessage += _("Synchronization aborted!"); @@ -450,41 +460,49 @@ void BatchStatusHandlerGui::initNewProcess(int objectsTotal, wxLongLong dataTota { currentProcess = processID; - if (currentProcess == StatusHandler::PROCESS_SCANNING) - syncStatusFrame->setCurrentStatus(SyncStatus::SCANNING); - - else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT) + switch (currentProcess) { + case StatusHandler::PROCESS_SCANNING: + syncStatusFrame->resetGauge(0, 0); //dummy call to initialize some gui elements (remaining time, speed) + syncStatusFrame->setCurrentStatus(SyncStatus::SCANNING); + break; + case StatusHandler::PROCESS_COMPARING_CONTENT: syncStatusFrame->resetGauge(objectsTotal, dataTotal); - syncStatusFrame->setCurrentStatus(SyncStatus::COMPARING); - } - - else if (currentProcess == StatusHandler::PROCESS_SYNCHRONIZING) - { + syncStatusFrame->setCurrentStatus(SyncStatus::COMPARING_CONTENT); + break; + case StatusHandler::PROCESS_SYNCHRONIZING: syncStatusFrame->resetGauge(objectsTotal, dataTotal); syncStatusFrame->setCurrentStatus(SyncStatus::SYNCHRONIZING); + break; + case StatusHandler::PROCESS_NONE: + assert(false); + break; } - else assert(false); } inline void BatchStatusHandlerGui::updateProcessedData(int objectsProcessed, wxLongLong dataProcessed) { - if (currentProcess == StatusHandler::PROCESS_SCANNING) - ; - else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT) - syncStatusFrame->incProgressIndicator_NoUpdate(objectsProcessed, dataProcessed); - else if (currentProcess == StatusHandler::PROCESS_SYNCHRONIZING) + switch (currentProcess) + { + case StatusHandler::PROCESS_SCANNING: + break; + case StatusHandler::PROCESS_COMPARING_CONTENT: + case StatusHandler::PROCESS_SYNCHRONIZING: syncStatusFrame->incProgressIndicator_NoUpdate(objectsProcessed, dataProcessed); - else assert(false); + break; + case StatusHandler::PROCESS_NONE: + assert(false); + break; + } } ErrorHandler::Response BatchStatusHandlerGui::reportError(const Zstring& errorMessage) { //add current time before error message - wxString errorWithTime = wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ") + errorMessage.c_str(); + const wxString errorWithTime = wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ") + errorMessage.c_str(); switch (m_handleError) { @@ -545,6 +563,8 @@ void BatchStatusHandlerGui::reportWarning(const Zstring& warningMessage, bool& d case xmlAccess::ON_ERROR_POPUP: case xmlAccess::ON_ERROR_EXIT: //show popup in this case also { + syncStatusFrame->updateStatusDialogNow(); + //show popup and ask user how to handle warning bool dontWarnAgain = false; WarningDlg* warningDlg = new WarningDlg(NULL, @@ -585,12 +605,12 @@ void BatchStatusHandlerGui::forceUiRefresh() void BatchStatusHandlerGui::abortThisProcess() { - abortRequested = true; + requestAbortion(); throw FreeFileSync::AbortThisProcess(); //abort can be triggered by syncStatusFrame } void BatchStatusHandlerGui::addFinalInfo(const Zstring& infoMessage) { - finalInfo = infoMessage.c_str(); + finalInfo = infoMessage.c_str(); } diff --git a/ui/dragAndDrop.cpp b/ui/dragAndDrop.cpp index c7aea906..2989e544 100644 --- a/ui/dragAndDrop.cpp +++ b/ui/dragAndDrop.cpp @@ -50,7 +50,7 @@ public: //create a custom event on drop window: execute event after file dropping is completed! (e.g. after mouse is released) FFSFileDropEvent evt(droppedFileName, dropWindow_); - dropWindow_->GetEventHandler()->AddPendingEvent(evt); + dropWindow_->AddPendingEvent(evt); } return false; } diff --git a/ui/gridView.cpp b/ui/gridView.cpp index ed950c15..aa309970 100644 --- a/ui/gridView.cpp +++ b/ui/gridView.cpp @@ -4,27 +4,43 @@ using FreeFileSync::GridView; -GridView::StatusInfo GridView::update( - const bool includeLeftOnly, - const bool includeRightOnly, - const bool includeLeftNewer, - const bool includeRightNewer, - const bool includeDifferent, - const bool includeEqual, - const bool hideFiltered) +GridView::GridView(FolderComparison& results) : + leftOnlyFilesActive(false), + rightOnlyFilesActive(false), + leftNewerFilesActive(false), + rightNewerFilesActive(false), + differentFilesActive(false), + equalFilesActive(false), + conflictFilesActive(false), + syncDirLeftActive(false), + syncDirRightActive(false), + syncDirNoneActive(false), + folderCmp(results) {} + + +GridView::StatusInfo::StatusInfo() : + existsLeftOnly(false), + existsRightOnly(false), + existsLeftNewer(false), + existsRightNewer(false), + existsDifferent(false), + existsEqual(false), + existsConflict(false), + + existsSyncDirLeft(false), + existsSyncDirRight(false), + existsSyncDirNone(false), + + filesOnLeftView(0), + foldersOnLeftView(0), + filesOnRightView(0), + foldersOnRightView(0), + objectsTotal(0) {} + +template <bool syncPreviewActive> +GridView::StatusInfo GridView::update_sub(const bool hideFiltered) { StatusInfo output; - output.existsLeftOnly = false; - output.existsRightOnly = false; - output.existsLeftNewer = false; - output.existsRightNewer = false; - output.existsDifferent = false; - output.existsEqual = false; - - output.filesOnLeftView = 0; - output.foldersOnLeftView = 0; - output.filesOnRightView = 0; - output.foldersOnRightView = 0; refView.clear(); @@ -32,6 +48,8 @@ GridView::StatusInfo GridView::update( { const FileComparison& fileCmp = j->fileCmp; + output.objectsTotal += j->fileCmp.size(); + RefIndex newEntry; newEntry.folderIndex = j - folderCmp.begin(); @@ -42,34 +60,68 @@ GridView::StatusInfo GridView::update( continue; //process UI filter settings - switch (i->cmpResult) + if (syncPreviewActive) //synchronization preview + { + //exclude result "==" + if (i->cmpResult == FILE_EQUAL) //note: consider elementsTotal()! + { + --output.objectsTotal; + continue; + } + + switch (i->direction) + { + case SYNC_DIR_LEFT: + output.existsSyncDirLeft = true; + if (!syncDirLeftActive) continue; + break; + case SYNC_DIR_RIGHT: + output.existsSyncDirRight = true; + if (!syncDirRightActive) continue; + break; + case SYNC_DIR_NONE: + output.existsSyncDirNone = true; + if (!syncDirNoneActive) continue; + break; + case SYNC_UNRESOLVED_CONFLICT: + output.existsConflict = true; + if (!conflictFilesActive) continue; + break; + } + } + else //comparison results view { - case FILE_LEFT_SIDE_ONLY: - output.existsLeftOnly = true; - if (!includeLeftOnly) continue; - break; - case FILE_RIGHT_SIDE_ONLY: - output.existsRightOnly = true; - if (!includeRightOnly) continue; - break; - case FILE_LEFT_NEWER: - output.existsLeftNewer = true; - if (!includeLeftNewer) continue; - break; - case FILE_RIGHT_NEWER: - output.existsRightNewer = true; - if (!includeRightNewer) continue; - break; - case FILE_DIFFERENT: - output.existsDifferent = true; - if (!includeDifferent) continue; - break; - case FILE_EQUAL: - output.existsEqual = true; - if (!includeEqual) continue; - break; - default: - assert (false); + switch (i->cmpResult) + { + case FILE_LEFT_SIDE_ONLY: + output.existsLeftOnly = true; + if (!leftOnlyFilesActive) continue; + break; + case FILE_RIGHT_SIDE_ONLY: + output.existsRightOnly = true; + if (!rightOnlyFilesActive) continue; + break; + case FILE_LEFT_NEWER: + output.existsLeftNewer = true; + if (!leftNewerFilesActive) continue; + break; + case FILE_RIGHT_NEWER: + output.existsRightNewer = true; + if (!rightNewerFilesActive) continue; + break; + case FILE_DIFFERENT: + output.existsDifferent = true; + if (!differentFilesActive) continue; + break; + case FILE_EQUAL: + output.existsEqual = true; + if (!equalFilesActive) continue; + break; + case FILE_CONFLICT: + output.existsConflict = true; + if (!conflictFilesActive) continue; + break; + } } //calculate total number of bytes for each side @@ -89,7 +141,6 @@ GridView::StatusInfo GridView::update( else if (i->fileDescrRight.objType == FileDescrLine::TYPE_DIRECTORY) ++output.foldersOnRightView; - newEntry.rowIndex = i - fileCmp.begin(); refView.push_back(newEntry); } @@ -105,6 +156,14 @@ GridView::StatusInfo GridView::update( } +GridView::StatusInfo GridView::update(const bool hideFiltered, const bool syncPreviewActive) +{ + return syncPreviewActive ? + update_sub<true>(hideFiltered) : + update_sub<false>(hideFiltered); +} + + void GridView::viewRefToFolderRef(const std::set<int>& viewRef, FolderCompRef& output) { output.clear(); @@ -121,13 +180,12 @@ void GridView::viewRefToFolderRef(const std::set<int>& viewRef, FolderCompRef& o } -unsigned int GridView::elementsTotal() const +bool GridView::refGridIsEmpty() const { - unsigned int total = 0; for (FolderComparison::const_iterator j = folderCmp.begin(); j != folderCmp.end(); ++j) - total += j->fileCmp.size(); + if (!j->fileCmp.empty()) return false; - return total; + return true; } @@ -140,9 +198,7 @@ void bubbleSort(FreeFileSync::FolderComparison& folderCmp, CompareFct compare) for (int j = 0; j <= i; ++j) if (compare(folderCmp[j + 1], folderCmp[j])) { - std::swap(folderCmp[j + 1].syncPair, folderCmp[j].syncPair); - folderCmp[j + 1].fileCmp.swap(folderCmp[j].fileCmp); - + folderCmp[j + 1].swap(folderCmp[j]); swapped = true; } @@ -158,8 +214,8 @@ void GridView::sortView(const SortType type, const bool onLeft, const bool ascen if (type == SORT_BY_DIRECTORY) { - //specialization: use own sorting function based on vector<FileCompareLine>::swap() - //bubble sort is no performance issue since number of folder pairs should be "small" + //specialization: use custom sorting function based on FolderComparison::swap() + //bubble sort is no performance issue since number of folder pairs should be "very small" if (ascending && onLeft) bubbleSort(folderCmp, sortByDirectory<ASCENDING, SORT_ON_LEFT>); else if (ascending && !onLeft) bubbleSort(folderCmp, sortByDirectory<ASCENDING, SORT_ON_RIGHT>); else if (!ascending && onLeft) bubbleSort(folderCmp, sortByDirectory<DESCENDING, SORT_ON_LEFT>); diff --git a/ui/gridView.h b/ui/gridView.h index b4101da7..2a4d4e29 100644 --- a/ui/gridView.h +++ b/ui/gridView.h @@ -10,15 +10,16 @@ namespace FreeFileSync class GridView { public: - GridView(FolderComparison& results) : folderCmp(results) {} + GridView(FolderComparison& results); const FileCompareLine& operator[] (unsigned row) const; + FileCompareLine& operator[] (unsigned row); //unsigned getResultsIndex(const unsigned viewIndex); //convert index on GridView to index on FolderComparison - unsigned int elementsOnView() const; + unsigned int elementsOnView() const; //only the currently visible elements - unsigned int elementsTotal() const; + bool refGridIsEmpty() const; //convert view references to FolderCompRef void viewRefToFolderRef(const std::set<int>& viewRef, FolderCompRef& output); @@ -27,29 +28,47 @@ namespace FreeFileSync struct StatusInfo { + StatusInfo(); + bool existsLeftOnly; bool existsRightOnly; bool existsLeftNewer; bool existsRightNewer; bool existsDifferent; bool existsEqual; + bool existsConflict; + + bool existsSyncDirLeft; + bool existsSyncDirRight; + bool existsSyncDirNone; unsigned int filesOnLeftView; unsigned int foldersOnLeftView; unsigned int filesOnRightView; unsigned int foldersOnRightView; + unsigned int objectsTotal; + wxULongLong filesizeLeftView; wxULongLong filesizeRightView; }; - StatusInfo update(const bool includeLeftOnly, - const bool includeRightOnly, - const bool includeLeftNewer, - const bool includeRightNewer, - const bool includeDifferent, - const bool includeEqual, - const bool hideFiltered); + StatusInfo update(const bool hideFiltered, const bool syncPreviewActive); + + //UI View Filter settings + //compare result + bool leftOnlyFilesActive; + bool rightOnlyFilesActive; + bool leftNewerFilesActive; + bool rightNewerFilesActive; + bool differentFilesActive; + bool equalFilesActive; + bool conflictFilesActive; + //sync preview + bool syncDirLeftActive; + bool syncDirRightActive; + bool syncDirNoneActive; + //sorting... enum SortType @@ -65,6 +84,9 @@ namespace FreeFileSync void sortView(const SortType type, const bool onLeft, const bool ascending); private: + template <bool syncPreviewActive> + StatusInfo update_sub(const bool hideFiltered); + struct RefIndex { unsigned int folderIndex; @@ -87,6 +109,13 @@ namespace FreeFileSync return folderCmp[folderInd].fileCmp[rowInd]; } + inline + FileCompareLine& GridView::operator[] (unsigned row) + { + //code re-use of const method: see Meyers Effective C++ + return const_cast<FileCompareLine&>(static_cast<const GridView&>(*this).operator[](row)); + } + inline unsigned int GridView::elementsOnView() const diff --git a/ui/guiGenerated.cpp b/ui/guiGenerated.cpp index c56fafbb..4819f9e6 100644 --- a/ui/guiGenerated.cpp +++ b/ui/guiGenerated.cpp @@ -26,6 +26,11 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_menuFile->AppendSeparator(); + m_menuItemSwitchView = new wxMenuItem( m_menuFile, wxID_ANY, wxString( _("S&witch view") ) + wxT('\t') + wxT("ALT-W"), wxEmptyString, wxITEM_NORMAL ); + m_menuFile->Append( m_menuItemSwitchView ); + + m_menuFile->AppendSeparator(); + wxMenuItem* m_menuItem14; m_menuItem14 = new wxMenuItem( m_menuFile, wxID_ANY, wxString( _("S&ave configuration") ) + wxT('\t') + wxT("CTRL-S"), wxEmptyString, wxITEM_NORMAL ); m_menuFile->Append( m_menuItem14 ); @@ -124,14 +129,14 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer30; bSizer30 = new wxBoxSizer( wxHORIZONTAL ); - m_buttonCompare = new wxButtonWithImage( m_panel71, wxID_OK, _("&Compare"), wxDefaultPosition, wxSize( 180,37 ), 0 ); + m_buttonCompare = new wxButtonWithImage( m_panel71, wxID_OK, _("Compare"), wxDefaultPosition, wxSize( 180,40 ), 0 ); m_buttonCompare->SetDefault(); m_buttonCompare->SetFont( wxFont( 14, 74, 90, 92, false, wxT("Arial Black") ) ); m_buttonCompare->SetToolTip( _("Compare both sides") ); bSizer30->Add( m_buttonCompare, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); - m_buttonAbort = new wxButton( m_panel71, wxID_CANCEL, _("&Abort"), wxDefaultPosition, wxSize( 180,37 ), 0 ); + m_buttonAbort = new wxButton( m_panel71, wxID_CANCEL, _("&Abort"), wxDefaultPosition, wxSize( 180,40 ), 0 ); m_buttonAbort->SetFont( wxFont( 14, 74, 90, 92, false, wxT("Tahoma") ) ); m_buttonAbort->Enable( false ); m_buttonAbort->Hide(); @@ -149,7 +154,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const wxBoxSizer* bSizer45; bSizer45 = new wxBoxSizer( wxVERTICAL ); - m_radioBtnSizeDate = new wxRadioButton( m_panel71, wxID_ANY, _("File size and date"), wxDefaultPosition, wxDefaultSize, 0 ); + m_radioBtnSizeDate = new wxRadioButton( m_panel71, wxID_ANY, _("File size and date"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP ); m_radioBtnSizeDate->SetValue( true ); m_radioBtnSizeDate->SetToolTip( _("Files are found equal if\n - filesize\n - last write time and date\nare the same.") ); @@ -177,7 +182,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizer6->Add( bSizer55, 0, wxALIGN_CENTER_VERTICAL, 5 ); - bSizer6->Add( 0, 0, 1, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer6->Add( 0, 0, 1, 0, 5 ); wxBoxSizer* bSizer56; bSizer56 = new wxBoxSizer( wxVERTICAL ); @@ -212,14 +217,24 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizer6->Add( bSizer56, 0, wxALIGN_CENTER_VERTICAL, 5 ); - m_buttonSync = new wxButtonWithImage( m_panel71, wxID_ANY, _("&Synchronize..."), wxDefaultPosition, wxSize( 180,37 ), 0 ); - m_buttonSync->SetFont( wxFont( 14, 74, 90, 92, false, wxT("Arial Black") ) ); - m_buttonSync->SetToolTip( _("Open synchronization dialog") ); - bSizer6->Add( m_buttonSync, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); + bSizer6->Add( 20, 0, 0, 0, 5 ); + + m_bpButtonSyncConfig = new wxBitmapButton( m_panel71, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,40 ), wxBU_AUTODRAW ); + m_bpButtonSyncConfig->SetToolTip( _("Synchronization settings") ); + + m_bpButtonSyncConfig->SetToolTip( _("Synchronization settings") ); + + bSizer6->Add( m_bpButtonSyncConfig, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 3 ); + + m_buttonStartSync = new wxButtonWithImage( m_panel71, wxID_ANY, _("Start"), wxDefaultPosition, wxSize( -1,40 ), 0 ); + m_buttonStartSync->SetFont( wxFont( 14, 74, 90, 92, false, wxT("Arial Black") ) ); + m_buttonStartSync->SetToolTip( _("Start synchronization") ); + bSizer6->Add( m_buttonStartSync, 0, wxALIGN_CENTER_VERTICAL, 5 ); - bSizer6->Add( 15, 0, 0, wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 ); + + bSizer6->Add( 15, 0, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_panel71->SetSizer( bSizer6 ); m_panel71->Layout(); @@ -259,12 +274,8 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const bSizerMiddle = new wxBoxSizer( wxHORIZONTAL ); - m_bpButtonSwap = new wxBitmapButton( m_panelTopMiddle, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); - m_bpButtonSwap->SetToolTip( _("Swap sides") ); - - m_bpButtonSwap->SetToolTip( _("Swap sides") ); - - bSizerMiddle->Add( m_bpButtonSwap, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + m_bpButtonSwitchView = new wxBitmapButton( m_panelTopMiddle, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 44,44 ), wxBU_AUTODRAW ); + bSizerMiddle->Add( m_bpButtonSwitchView, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); bSizer93->Add( bSizerMiddle, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 ); @@ -393,7 +404,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_gridMiddle->SetMargins( 0, 0 ); // Columns - m_gridMiddle->SetColSize( 0, 45 ); + m_gridMiddle->SetColSize( 0, 60 ); m_gridMiddle->EnableDragColMove( false ); m_gridMiddle->EnableDragColSize( false ); m_gridMiddle->SetColLabelSize( 20 ); @@ -457,7 +468,8 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_panel4 = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); bSizer3 = new wxBoxSizer( wxHORIZONTAL ); - bSizer58 = new wxBoxSizer( wxVERTICAL ); + wxBoxSizer* bSizer120; + bSizer120 = new wxBoxSizer( wxVERTICAL ); wxStaticBoxSizer* sbSizer16; sbSizer16 = new wxStaticBoxSizer( new wxStaticBox( m_panel4, wxID_ANY, _("Configuration") ), wxHORIZONTAL ); @@ -467,7 +479,7 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_bpButtonSave->SetToolTip( _("Save current configuration to file") ); - sbSizer16->Add( m_bpButtonSave, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 ); + sbSizer16->Add( m_bpButtonSave, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_bpButtonLoad = new wxBitmapButton( m_panel4, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); m_bpButtonLoad->SetToolTip( _("Load configuration from file") ); @@ -481,14 +493,11 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_choiceHistory->SetSelection( 0 ); m_choiceHistory->SetToolTip( _("Load configuration history (press DEL to delete items)") ); - sbSizer16->Add( m_choiceHistory, 1, wxALIGN_CENTER_VERTICAL, 5 ); - - bSizer58->Add( sbSizer16, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); - + sbSizer16->Add( m_choiceHistory, 0, wxALIGN_CENTER_VERTICAL, 5 ); - bSizer58->Add( 0, 4, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); + bSizer120->Add( sbSizer16, 0, wxALIGN_CENTER_VERTICAL, 5 ); - bSizer3->Add( bSizer58, 1, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer3->Add( bSizer120, 1, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxLEFT, 5 ); m_panel112 = new wxPanel( m_panel4, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* bSizer64; @@ -519,6 +528,18 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_bpButtonRightOnly = new wxBitmapButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); sbSizer31->Add( m_bpButtonRightOnly, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_bpButtonSyncDirLeft = new wxBitmapButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); + sbSizer31->Add( m_bpButtonSyncDirLeft, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_bpButtonSyncDirNone = new wxBitmapButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); + sbSizer31->Add( m_bpButtonSyncDirNone, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_bpButtonSyncDirRight = new wxBitmapButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); + sbSizer31->Add( m_bpButtonSyncDirRight, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_bpButtonConflict = new wxBitmapButton( m_panel112, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW ); + sbSizer31->Add( m_bpButtonConflict, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 ); + sbSizer31->Add( 0, 0, 1, wxEXPAND, 5 ); @@ -527,19 +548,98 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_panel112->SetSizer( bSizer64 ); m_panel112->Layout(); bSizer64->Fit( m_panel112 ); - bSizer3->Add( m_panel112, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM, 4 ); + bSizer3->Add( m_panel112, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); wxBoxSizer* bSizer66; - bSizer66 = new wxBoxSizer( wxVERTICAL ); + bSizer66 = new wxBoxSizer( wxHORIZONTAL ); + + + bSizer66->Add( 0, 0, 1, 0, 5 ); + + m_panelSyncPreview = new wxPanel( m_panel4, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); + wxBoxSizer* bSizer121; + bSizer121 = new wxBoxSizer( wxVERTICAL ); + + wxStaticBoxSizer* sbSizer161; + sbSizer161 = new wxStaticBoxSizer( new wxStaticBox( m_panelSyncPreview, wxID_ANY, _("Preview") ), wxHORIZONTAL ); + + wxFlexGridSizer* fgSizer5; + fgSizer5 = new wxFlexGridSizer( 2, 2, 0, 5 ); + fgSizer5->SetFlexibleDirection( wxHORIZONTAL ); + fgSizer5->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_bitmapCreate = new wxStaticBitmap( m_panelSyncPreview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + m_bitmapCreate->SetToolTip( _("Number of files and directories that will be created") ); + + fgSizer5->Add( m_bitmapCreate, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); + + m_textCtrlCreate = new wxTextCtrl( m_panelSyncPreview, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 80,-1 ), wxTE_READONLY ); + m_textCtrlCreate->SetFont( wxFont( 8, 74, 90, 90, false, wxT("Tahoma") ) ); + m_textCtrlCreate->SetBackgroundColour( wxColour( 222, 222, 236 ) ); + m_textCtrlCreate->SetToolTip( _("Number of files and directories that will be created") ); + + fgSizer5->Add( m_textCtrlCreate, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_bitmapDelete = new wxStaticBitmap( m_panelSyncPreview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + m_bitmapDelete->SetToolTip( _("Number of files and directories that will be deleted") ); + + fgSizer5->Add( m_bitmapDelete, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + m_textCtrlDelete = new wxTextCtrl( m_panelSyncPreview, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 80,-1 ), wxTE_READONLY ); + m_textCtrlDelete->SetFont( wxFont( 8, 74, 90, 90, false, wxT("Tahoma") ) ); + m_textCtrlDelete->SetBackgroundColour( wxColour( 222, 222, 236 ) ); + m_textCtrlDelete->SetToolTip( _("Number of files and directories that will be deleted") ); + + fgSizer5->Add( m_textCtrlDelete, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + sbSizer161->Add( fgSizer5, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 ); + + wxFlexGridSizer* fgSizer6; + fgSizer6 = new wxFlexGridSizer( 2, 2, 0, 5 ); + fgSizer6->SetFlexibleDirection( wxHORIZONTAL ); + fgSizer6->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + m_bitmapUpdate = new wxStaticBitmap( m_panelSyncPreview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + m_bitmapUpdate->SetToolTip( _("Number of files that will be overwritten") ); + + fgSizer6->Add( m_bitmapUpdate, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); + + m_textCtrlUpdate = new wxTextCtrl( m_panelSyncPreview, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 80,-1 ), wxTE_READONLY ); + m_textCtrlUpdate->SetFont( wxFont( 8, 74, 90, 90, false, wxT("Tahoma") ) ); + m_textCtrlUpdate->SetBackgroundColour( wxColour( 222, 222, 236 ) ); + m_textCtrlUpdate->SetToolTip( _("Number of files that will be overwritten") ); + + fgSizer6->Add( m_textCtrlUpdate, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_bitmapData = new wxStaticBitmap( m_panelSyncPreview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, 0 ); + m_bitmapData->SetToolTip( _("Total amount of data that will be transferred") ); + + fgSizer6->Add( m_bitmapData, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_CENTER_HORIZONTAL, 5 ); + + m_textCtrlData = new wxTextCtrl( m_panelSyncPreview, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 80,-1 ), wxTE_READONLY ); + m_textCtrlData->SetFont( wxFont( 8, 74, 90, 90, false, wxT("Tahoma") ) ); + m_textCtrlData->SetBackgroundColour( wxColour( 222, 222, 236 ) ); + m_textCtrlData->SetToolTip( _("Total amount of data that will be transferred") ); + + fgSizer6->Add( m_textCtrlData, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + sbSizer161->Add( fgSizer6, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 ); + + bSizer121->Add( sbSizer161, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_panelSyncPreview->SetSizer( bSizer121 ); + m_panelSyncPreview->Layout(); + bSizer121->Fit( m_panelSyncPreview ); + bSizer66->Add( m_panelSyncPreview, 0, wxALIGN_CENTER_VERTICAL, 5 ); m_bpButton10 = new wxBitmapButton( m_panel4, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 50,50 ), wxBU_AUTODRAW ); m_bpButton10->SetToolTip( _("Quit") ); m_bpButton10->SetToolTip( _("Quit") ); - bSizer66->Add( m_bpButton10, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL, 5 ); + bSizer66->Add( m_bpButton10, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT, 5 ); - bSizer3->Add( bSizer66, 1, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer3->Add( bSizer66, 1, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT, 5 ); m_panel4->SetSizer( bSizer3 ); m_panel4->Layout(); @@ -622,7 +722,8 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const // Connect Events this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDialogGenerated::OnClose ) ); this->Connect( m_menuItem10->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnCompare ) ); - this->Connect( m_menuItem11->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnSync ) ); + this->Connect( m_menuItem11->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnStartSync ) ); + this->Connect( m_menuItemSwitchView->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnSwitchView ) ); this->Connect( m_menuItem14->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuSaveConfig ) ); this->Connect( m_menuItem13->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLoadConfig ) ); this->Connect( m_menuItem4->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuQuit ) ); @@ -652,10 +753,11 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_bpButtonFilter->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnFilterButton ), NULL, this ); m_hyperlinkCfgFilter->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( MainDialogGenerated::OnConfigureFilter ), NULL, this ); m_checkBoxHideFilt->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnHideFilteredButton ), NULL, this ); - m_buttonSync->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSync ), NULL, this ); + m_bpButtonSyncConfig->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncSettings ), NULL, this ); + m_buttonStartSync->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnStartSync ), NULL, this ); m_directoryLeft->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( MainDialogGenerated::OnFolderHistoryKeyEvent ), NULL, this ); m_dirPickerLeft->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this ); - m_bpButtonSwap->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSwapDirs ), NULL, this ); + m_bpButtonSwitchView->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSwitchView ), NULL, this ); m_bpButtonAddPair->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnAddFolderPair ), NULL, this ); m_directoryRight->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( MainDialogGenerated::OnFolderHistoryKeyEvent ), NULL, this ); m_dirPickerRight->Connect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this ); @@ -679,6 +781,10 @@ MainDialogGenerated::MainDialogGenerated( wxWindow* parent, wxWindowID id, const m_bpButtonDifferent->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnDifferentFiles ), NULL, this ); m_bpButtonRightNewer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRightNewerFiles ), NULL, this ); m_bpButtonRightOnly->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRightOnlyFiles ), NULL, this ); + m_bpButtonSyncDirLeft->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDirLeft ), NULL, this ); + m_bpButtonSyncDirNone->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDirNone ), NULL, this ); + m_bpButtonSyncDirRight->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDirRight ), NULL, this ); + m_bpButtonConflict->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConflictFiles ), NULL, this ); m_bpButton10->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnQuit ), NULL, this ); } @@ -687,7 +793,8 @@ MainDialogGenerated::~MainDialogGenerated() // Disconnect Events this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( MainDialogGenerated::OnClose ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnCompare ) ); - this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnSync ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnStartSync ) ); + this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnSwitchView ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuSaveConfig ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuLoadConfig ) ); this->Disconnect( wxID_ANY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( MainDialogGenerated::OnMenuQuit ) ); @@ -717,10 +824,11 @@ MainDialogGenerated::~MainDialogGenerated() m_bpButtonFilter->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnFilterButton ), NULL, this ); m_hyperlinkCfgFilter->Disconnect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( MainDialogGenerated::OnConfigureFilter ), NULL, this ); m_checkBoxHideFilt->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnHideFilteredButton ), NULL, this ); - m_buttonSync->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSync ), NULL, this ); + m_bpButtonSyncConfig->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncSettings ), NULL, this ); + m_buttonStartSync->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnStartSync ), NULL, this ); m_directoryLeft->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( MainDialogGenerated::OnFolderHistoryKeyEvent ), NULL, this ); m_dirPickerLeft->Disconnect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this ); - m_bpButtonSwap->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSwapDirs ), NULL, this ); + m_bpButtonSwitchView->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSwitchView ), NULL, this ); m_bpButtonAddPair->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnAddFolderPair ), NULL, this ); m_directoryRight->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( MainDialogGenerated::OnFolderHistoryKeyEvent ), NULL, this ); m_dirPickerRight->Disconnect( wxEVT_COMMAND_DIRPICKER_CHANGED, wxFileDirPickerEventHandler( MainDialogGenerated::OnDirSelected ), NULL, this ); @@ -744,6 +852,10 @@ MainDialogGenerated::~MainDialogGenerated() m_bpButtonDifferent->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnDifferentFiles ), NULL, this ); m_bpButtonRightNewer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRightNewerFiles ), NULL, this ); m_bpButtonRightOnly->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnRightOnlyFiles ), NULL, this ); + m_bpButtonSyncDirLeft->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDirLeft ), NULL, this ); + m_bpButtonSyncDirNone->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDirNone ), NULL, this ); + m_bpButtonSyncDirRight->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnSyncDirRight ), NULL, this ); + m_bpButtonConflict->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnConflictFiles ), NULL, this ); m_bpButton10->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainDialogGenerated::OnQuit ), NULL, this ); } @@ -784,15 +896,15 @@ FolderPairGenerated::FolderPairGenerated( wxWindow* parent, wxWindowID id, const bSizer96->Add( 0, 15, 0, 0, 5 ); - m_bitmap23 = new wxStaticBitmap( m_panel21, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 45,17 ), 0 ); + m_bitmap23 = new wxStaticBitmap( m_panel21, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 44,17 ), 0 ); m_bitmap23->SetToolTip( _("Folder pair") ); - bSizer96->Add( m_bitmap23, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); + bSizer96->Add( m_bitmap23, 0, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT, 8 ); m_panel21->SetSizer( bSizer96 ); m_panel21->Layout(); bSizer96->Fit( m_panel21 ); - bSizer95->Add( m_panel21, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND|wxRIGHT|wxLEFT, 5 ); + bSizer95->Add( m_panel21, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT|wxEXPAND, 5 ); m_panel20->SetSizer( bSizer95 ); m_panel20->Layout(); @@ -1079,69 +1191,109 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS wxGridSizer* gSizer3; gSizer3 = new wxGridSizer( 1, 2, 0, 5 ); - m_staticText211 = new wxStaticText( m_panelOverview, wxID_ANY, _("Result"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText211->Wrap( -1 ); - m_staticText211->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Tahoma") ) ); + m_staticText21 = new wxStaticText( m_panelOverview, wxID_ANY, _("Result"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText21->Wrap( -1 ); + m_staticText21->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Tahoma") ) ); - gSizer3->Add( m_staticText211, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + gSizer3->Add( m_staticText21, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_staticText311 = new wxStaticText( m_panelOverview, wxID_ANY, _("Action"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText311->Wrap( -1 ); - m_staticText311->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Tahoma") ) ); + m_staticText31 = new wxStaticText( m_panelOverview, wxID_ANY, _("Action"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText31->Wrap( -1 ); + m_staticText31->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Tahoma") ) ); - gSizer3->Add( m_staticText311, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + gSizer3->Add( m_staticText31, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); sbSizer61->Add( gSizer3, 0, wxEXPAND, 5 ); m_staticline3 = new wxStaticLine( m_panelOverview, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); sbSizer61->Add( m_staticline3, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxTOP|wxBOTTOM, 5 ); - wxGridSizer* gSizer1; - gSizer1 = new wxGridSizer( 5, 2, 0, 5 ); + wxBoxSizer* bSizer121; + bSizer121 = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizer122; + bSizer122 = new wxBoxSizer( wxHORIZONTAL ); + + m_bitmapLeftOnly = new wxStaticBitmap( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + m_bitmapLeftOnly->SetToolTip( _("Files/folders that exist on left side only") ); + + bSizer122->Add( m_bitmapLeftOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer122->Add( 5, 0, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_bpButtonLeftOnly = new wxBitmapButton( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + bSizer122->Add( m_bpButtonLeftOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bitmap13 = new wxStaticBitmap( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); - m_bitmap13->SetToolTip( _("Files/folders that exist on left side only") ); + bSizer121->Add( bSizer122, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); - gSizer1->Add( m_bitmap13, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + wxBoxSizer* bSizer123; + bSizer123 = new wxBoxSizer( wxHORIZONTAL ); - m_bpButton5 = new wxBitmapButton( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); - gSizer1->Add( m_bpButton5, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + m_bitmapRightOnly = new wxStaticBitmap( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + m_bitmapRightOnly->SetToolTip( _("Files/folders that exist on right side only") ); - m_bitmap14 = new wxStaticBitmap( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); - m_bitmap14->SetToolTip( _("Files/folders that exist on right side only") ); + bSizer123->Add( m_bitmapRightOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - gSizer1->Add( m_bitmap14, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButton6 = new wxBitmapButton( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); - gSizer1->Add( m_bpButton6, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer123->Add( 5, 0, 0, 0, 5 ); - m_bitmap15 = new wxStaticBitmap( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); - m_bitmap15->SetToolTip( _("Files that exist on both sides, left one is newer") ); + m_bpButtonRightOnly = new wxBitmapButton( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + bSizer123->Add( m_bpButtonRightOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - gSizer1->Add( m_bitmap15, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer121->Add( bSizer123, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bpButton7 = new wxBitmapButton( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); - gSizer1->Add( m_bpButton7, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + wxBoxSizer* bSizer124; + bSizer124 = new wxBoxSizer( wxHORIZONTAL ); - m_bitmap16 = new wxStaticBitmap( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); - m_bitmap16->SetToolTip( _("Files that exist on both sides, right one is newer") ); + m_bitmapLeftNewer = new wxStaticBitmap( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + m_bitmapLeftNewer->SetToolTip( _("Files that exist on both sides, left one is newer") ); - gSizer1->Add( m_bitmap16, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer124->Add( m_bitmapLeftNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButton8 = new wxBitmapButton( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); - gSizer1->Add( m_bpButton8, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bitmap17 = new wxStaticBitmap( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); - m_bitmap17->SetToolTip( _("dummy") ); + bSizer124->Add( 5, 0, 0, 0, 5 ); - gSizer1->Add( m_bitmap17, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + m_bpButtonLeftNewer = new wxBitmapButton( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + bSizer124->Add( m_bpButtonLeftNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButton9 = new wxBitmapButton( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); - gSizer1->Add( m_bpButton9, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer121->Add( bSizer124, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); - sbSizer61->Add( gSizer1, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 ); + wxBoxSizer* bSizer125; + bSizer125 = new wxBoxSizer( wxHORIZONTAL ); - bSizer120->Add( sbSizer61, 0, 0, 5 ); + m_bitmapRightNewer = new wxStaticBitmap( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + m_bitmapRightNewer->SetToolTip( _("Files that exist on both sides, right one is newer") ); + + bSizer125->Add( m_bitmapRightNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer125->Add( 5, 0, 0, 0, 5 ); + + m_bpButtonRightNewer = new wxBitmapButton( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + bSizer125->Add( m_bpButtonRightNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + bSizer121->Add( bSizer125, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); + + wxBoxSizer* bSizer126; + bSizer126 = new wxBoxSizer( wxHORIZONTAL ); + + m_bitmapDifferent = new wxStaticBitmap( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + m_bitmapDifferent->SetToolTip( _("Files that exist on both sides and have different content") ); + + bSizer126->Add( m_bitmapDifferent, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer126->Add( 5, 0, 0, 0, 5 ); + + m_bpButtonDifferent = new wxBitmapButton( m_panelOverview, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + bSizer126->Add( m_bpButtonDifferent, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + bSizer121->Add( bSizer126, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); + + sbSizer61->Add( bSizer121, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); + + bSizer120->Add( sbSizer61, 0, wxALIGN_CENTER_VERTICAL, 5 ); bSizer67->Add( bSizer120, 1, wxALL, 10 ); @@ -1180,7 +1332,7 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_textCtrlInclude = new wxTextCtrl( m_panelFilter, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE ); fgSizer3->Add( m_textCtrlInclude, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); - sbSizer8->Add( fgSizer3, 0, wxEXPAND, 5 ); + sbSizer8->Add( fgSizer3, 1, wxEXPAND, 5 ); wxFlexGridSizer* fgSizer4; fgSizer4 = new wxFlexGridSizer( 2, 2, 0, 0 ); @@ -1206,7 +1358,7 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_textCtrlExclude = new wxTextCtrl( m_panelFilter, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE ); fgSizer4->Add( m_textCtrlExclude, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); - sbSizer8->Add( fgSizer4, 0, wxEXPAND, 5 ); + sbSizer8->Add( fgSizer4, 1, wxEXPAND, 5 ); bSizer114->Add( sbSizer8, 1, wxALL|wxEXPAND, 10 ); @@ -1284,11 +1436,11 @@ BatchDlgGenerated::BatchDlgGenerated( wxWindow* parent, wxWindowID id, const wxS m_checkBoxUseRecycler->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnSelectRecycleBin ), NULL, this ); m_checkBoxFilter->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCheckFilter ), NULL, this ); m_checkBoxSilent->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCheckLogging ), NULL, this ); - m_bpButton5->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnExLeftSideOnly ), NULL, this ); - m_bpButton6->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnExRightSideOnly ), NULL, this ); - m_bpButton7->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnLeftNewer ), NULL, this ); - m_bpButton8->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnRightNewer ), NULL, this ); - m_bpButton9->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnDifferent ), NULL, this ); + m_bpButtonLeftOnly->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnExLeftSideOnly ), NULL, this ); + m_bpButtonRightOnly->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnExRightSideOnly ), NULL, this ); + m_bpButtonLeftNewer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnLeftNewer ), NULL, this ); + m_bpButtonRightNewer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnRightNewer ), NULL, this ); + m_bpButtonDifferent->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnDifferent ), NULL, this ); m_buttonSave->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnSaveBatchJob ), NULL, this ); m_buttonLoad->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnLoadBatchJob ), NULL, this ); m_button6->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCancel ), NULL, this ); @@ -1304,11 +1456,11 @@ BatchDlgGenerated::~BatchDlgGenerated() m_checkBoxUseRecycler->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnSelectRecycleBin ), NULL, this ); m_checkBoxFilter->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCheckFilter ), NULL, this ); m_checkBoxSilent->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCheckLogging ), NULL, this ); - m_bpButton5->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnExLeftSideOnly ), NULL, this ); - m_bpButton6->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnExRightSideOnly ), NULL, this ); - m_bpButton7->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnLeftNewer ), NULL, this ); - m_bpButton8->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnRightNewer ), NULL, this ); - m_bpButton9->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnDifferent ), NULL, this ); + m_bpButtonLeftOnly->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnExLeftSideOnly ), NULL, this ); + m_bpButtonRightOnly->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnExRightSideOnly ), NULL, this ); + m_bpButtonLeftNewer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnLeftNewer ), NULL, this ); + m_bpButtonRightNewer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnRightNewer ), NULL, this ); + m_bpButtonDifferent->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnDifferent ), NULL, this ); m_buttonSave->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnSaveBatchJob ), NULL, this ); m_buttonLoad->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnLoadBatchJob ), NULL, this ); m_button6->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( BatchDlgGenerated::OnCancel ), NULL, this ); @@ -1473,40 +1625,6 @@ SyncDlgGenerated::SyncDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr wxBoxSizer* bSizer29; bSizer29 = new wxBoxSizer( wxVERTICAL ); - bSizer201 = new wxBoxSizer( wxHORIZONTAL ); - - m_button18 = new wxButtonWithImage( this, wxID_OK, _("&Start"), wxDefaultPosition, wxSize( 140,58 ), 0 ); - m_button18->SetDefault(); - m_button18->SetFont( wxFont( 16, 74, 90, 92, false, wxT("Arial Black") ) ); - m_button18->SetToolTip( _("Start synchronization") ); - - bSizer201->Add( m_button18, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - - bSizer201->Add( 18, 0, 0, wxEXPAND, 5 ); - - wxBoxSizer* bSizer38; - bSizer38 = new wxBoxSizer( wxVERTICAL ); - - m_checkBoxUseRecycler = new wxCheckBox( this, wxID_ANY, _("Use Recycle Bin"), wxDefaultPosition, wxDefaultSize, 0 ); - - m_checkBoxUseRecycler->SetToolTip( _("Use Recycle Bin when deleting or overwriting files during synchronization") ); - - bSizer38->Add( m_checkBoxUseRecycler, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); - - m_checkBoxIgnoreErrors = new wxCheckBox( this, wxID_ANY, _("Ignore errors"), wxDefaultPosition, wxDefaultSize, 0 ); - - m_checkBoxIgnoreErrors->SetToolTip( _("Hides error messages during synchronization:\nThey are collected and shown as a list at the end of the process") ); - - bSizer38->Add( m_checkBoxIgnoreErrors, 0, wxALL, 5 ); - - bSizer201->Add( bSizer38, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - bSizer29->Add( bSizer201, 1, 0, 5 ); - - - bSizer29->Add( 0, 5, 0, 0, 5 ); - wxStaticBoxSizer* sbSizer7; sbSizer7 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, wxEmptyString ), wxVERTICAL ); @@ -1595,100 +1713,47 @@ SyncDlgGenerated::SyncDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr bSizer29->Add( sbSizer7, 0, wxEXPAND, 5 ); - bSizer29->Add( 0, 5, 0, 0, 5 ); - - wxBoxSizer* bSizer291; - bSizer291 = new wxBoxSizer( wxHORIZONTAL ); - - m_button6 = new wxButton( this, wxID_APPLY, _("&Apply"), wxDefaultPosition, wxSize( 100,32 ), 0 ); - m_button6->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); - - bSizer291->Add( m_button6, 0, wxALIGN_BOTTOM, 5 ); - - m_button16 = new wxButton( this, wxID_CANCEL, _("dummy"), wxDefaultPosition, wxSize( 0,0 ), 0 ); - bSizer291->Add( m_button16, 0, wxALIGN_BOTTOM, 5 ); - - - bSizer291->Add( 20, 0, 1, wxALIGN_CENTER_VERTICAL, 5 ); - - wxStaticBoxSizer* sbSizer16; - sbSizer16 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Preview") ), wxHORIZONTAL ); - - wxFlexGridSizer* fgSizer5; - fgSizer5 = new wxFlexGridSizer( 2, 2, 0, 5 ); - fgSizer5->SetFlexibleDirection( wxHORIZONTAL ); - fgSizer5->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); - - m_staticText37 = new wxStaticText( this, wxID_ANY, _("Create:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText37->Wrap( -1 ); - m_staticText37->SetFont( wxFont( 10, 74, 93, 90, false, wxT("Tahoma") ) ); - m_staticText37->SetToolTip( _("Number of files and directories that will be created") ); + bSizer29->Add( 0, 5, 1, 0, 5 ); - fgSizer5->Add( m_staticText37, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer201 = new wxBoxSizer( wxHORIZONTAL ); - m_textCtrlCreate = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 80,-1 ), wxTE_READONLY ); - m_textCtrlCreate->SetFont( wxFont( 8, 74, 90, 90, false, wxT("Tahoma") ) ); - m_textCtrlCreate->SetBackgroundColour( wxColour( 222, 222, 236 ) ); - m_textCtrlCreate->SetToolTip( _("Number of files and directories that will be created") ); + m_checkBoxUseRecycler = new wxCheckBox( this, wxID_ANY, _("Use Recycle Bin"), wxDefaultPosition, wxDefaultSize, 0 ); - fgSizer5->Add( m_textCtrlCreate, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_checkBoxUseRecycler->SetToolTip( _("Use Recycle Bin when deleting or overwriting files during synchronization") ); - m_staticText14 = new wxStaticText( this, wxID_ANY, _("Delete:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText14->Wrap( -1 ); - m_staticText14->SetFont( wxFont( 10, 74, 93, 90, false, wxT("Tahoma") ) ); - m_staticText14->SetToolTip( _("Number of files and directories that will be deleted") ); + bSizer201->Add( m_checkBoxUseRecycler, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); - fgSizer5->Add( m_staticText14, 0, wxALIGN_CENTER_VERTICAL, 5 ); + m_checkBoxIgnoreErrors = new wxCheckBox( this, wxID_ANY, _("Ignore errors"), wxDefaultPosition, wxDefaultSize, 0 ); - m_textCtrlDelete = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 80,-1 ), wxTE_READONLY ); - m_textCtrlDelete->SetFont( wxFont( 8, 74, 90, 90, false, wxT("Tahoma") ) ); - m_textCtrlDelete->SetBackgroundColour( wxColour( 222, 222, 236 ) ); - m_textCtrlDelete->SetToolTip( _("Number of files and directories that will be deleted") ); + m_checkBoxIgnoreErrors->SetToolTip( _("Hides error messages during synchronization:\nThey are collected and shown as a list at the end of the process") ); - fgSizer5->Add( m_textCtrlDelete, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer201->Add( m_checkBoxIgnoreErrors, 0, wxALL, 5 ); - sbSizer16->Add( fgSizer5, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer29->Add( bSizer201, 0, 0, 5 ); - wxFlexGridSizer* fgSizer6; - fgSizer6 = new wxFlexGridSizer( 2, 2, 0, 5 ); - fgSizer6->SetFlexibleDirection( wxHORIZONTAL ); - fgSizer6->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); - m_staticText42 = new wxStaticText( this, wxID_ANY, _("Update:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText42->Wrap( -1 ); - m_staticText42->SetFont( wxFont( 10, 74, 93, 90, false, wxT("Tahoma") ) ); - m_staticText42->SetToolTip( _("Number of files that will be overwritten") ); + bSizer29->Add( 0, 5, 1, 0, 5 ); - fgSizer6->Add( m_staticText42, 0, wxALIGN_CENTER_VERTICAL, 5 ); + wxBoxSizer* bSizer291; + bSizer291 = new wxBoxSizer( wxHORIZONTAL ); - m_textCtrlUpdate = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 80,-1 ), wxTE_READONLY ); - m_textCtrlUpdate->SetFont( wxFont( 8, 74, 90, 90, false, wxT("Tahoma") ) ); - m_textCtrlUpdate->SetBackgroundColour( wxColour( 222, 222, 236 ) ); - m_textCtrlUpdate->SetToolTip( _("Number of files that will be overwritten") ); + m_button6 = new wxButton( this, wxID_OK, _("&Apply"), wxDefaultPosition, wxSize( 120,35 ), 0 ); + m_button6->SetDefault(); + m_button6->SetFont( wxFont( 10, 74, 90, 92, false, wxT("Tahoma") ) ); - fgSizer6->Add( m_textCtrlUpdate, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer291->Add( m_button6, 0, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); - m_staticText43 = new wxStaticText( this, wxID_ANY, _("Data:"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText43->Wrap( -1 ); - m_staticText43->SetFont( wxFont( 10, 74, 93, 90, false, wxT("Tahoma") ) ); - m_staticText43->SetToolTip( _("Total amount of data that will be transferred") ); + m_button16 = new wxButton( this, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxSize( -1,30 ), 0 ); + m_button16->SetFont( wxFont( 10, 74, 90, 90, false, wxT("Tahoma") ) ); - fgSizer6->Add( m_staticText43, 0, wxALIGN_CENTER_VERTICAL, 5 ); + bSizer291->Add( m_button16, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); - m_textCtrlData = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( 80,-1 ), wxTE_READONLY ); - m_textCtrlData->SetFont( wxFont( 8, 74, 90, 90, false, wxT("Tahoma") ) ); - m_textCtrlData->SetBackgroundColour( wxColour( 222, 222, 236 ) ); - m_textCtrlData->SetToolTip( _("Total amount of data that will be transferred") ); - fgSizer6->Add( m_textCtrlData, 0, wxALIGN_CENTER_VERTICAL, 5 ); - - sbSizer16->Add( fgSizer6, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); - - bSizer291->Add( sbSizer16, 0, wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); + bSizer291->Add( 20, 0, 1, wxALIGN_CENTER_VERTICAL, 5 ); bSizer29->Add( bSizer291, 0, wxEXPAND, 5 ); - bSizer181->Add( bSizer29, 0, 0, 5 ); + bSizer181->Add( bSizer29, 0, wxEXPAND, 5 ); bSizer181->Add( 10, 0, 0, 0, 5 ); @@ -1716,50 +1781,90 @@ SyncDlgGenerated::SyncDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr m_staticline3 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); sbSizer6->Add( m_staticline3, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxTOP|wxBOTTOM, 5 ); - wxGridSizer* gSizer1; - gSizer1 = new wxGridSizer( 5, 2, 0, 5 ); + wxBoxSizer* bSizer121; + bSizer121 = new wxBoxSizer( wxVERTICAL ); + + wxBoxSizer* bSizer122; + bSizer122 = new wxBoxSizer( wxHORIZONTAL ); + + m_bitmapLeftOnly = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + m_bitmapLeftOnly->SetToolTip( _("Files/folders that exist on left side only") ); + + bSizer122->Add( m_bitmapLeftOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer122->Add( 5, 0, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + m_bpButtonLeftOnly = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + bSizer122->Add( m_bpButtonLeftOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + bSizer121->Add( bSizer122, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); + + wxBoxSizer* bSizer123; + bSizer123 = new wxBoxSizer( wxHORIZONTAL ); + + m_bitmapRightOnly = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + m_bitmapRightOnly->SetToolTip( _("Files/folders that exist on right side only") ); + + bSizer123->Add( m_bitmapRightOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + - m_bitmap13 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); - m_bitmap13->SetToolTip( _("Files/folders that exist on left side only") ); + bSizer123->Add( 5, 0, 0, 0, 5 ); - gSizer1->Add( m_bitmap13, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + m_bpButtonRightOnly = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + bSizer123->Add( m_bpButtonRightOnly, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButton5 = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); - gSizer1->Add( m_bpButton5, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer121->Add( bSizer123, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); - m_bitmap14 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); - m_bitmap14->SetToolTip( _("Files/folders that exist on right side only") ); + wxBoxSizer* bSizer124; + bSizer124 = new wxBoxSizer( wxHORIZONTAL ); - gSizer1->Add( m_bitmap14, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + m_bitmapLeftNewer = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + m_bitmapLeftNewer->SetToolTip( _("Files that exist on both sides, left one is newer") ); - m_bpButton6 = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); - gSizer1->Add( m_bpButton6, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer124->Add( m_bitmapLeftNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bitmap15 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); - m_bitmap15->SetToolTip( _("Files that exist on both sides, left one is newer") ); - gSizer1->Add( m_bitmap15, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer124->Add( 5, 0, 0, 0, 5 ); - m_bpButton7 = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); - gSizer1->Add( m_bpButton7, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + m_bpButtonLeftNewer = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + bSizer124->Add( m_bpButtonLeftNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bitmap16 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); - m_bitmap16->SetToolTip( _("Files that exist on both sides, right one is newer") ); + bSizer121->Add( bSizer124, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); - gSizer1->Add( m_bitmap16, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + wxBoxSizer* bSizer125; + bSizer125 = new wxBoxSizer( wxHORIZONTAL ); - m_bpButton8 = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); - gSizer1->Add( m_bpButton8, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + m_bitmapRightNewer = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + m_bitmapRightNewer->SetToolTip( _("Files that exist on both sides, right one is newer") ); - m_bitmap17 = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); - m_bitmap17->SetToolTip( _("dummy") ); + bSizer125->Add( m_bitmapRightNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - gSizer1->Add( m_bitmap17, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); - m_bpButton9 = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); - gSizer1->Add( m_bpButton9, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + bSizer125->Add( 5, 0, 0, 0, 5 ); - sbSizer6->Add( gSizer1, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND, 5 ); + m_bpButtonRightNewer = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + bSizer125->Add( m_bpButtonRightNewer, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + bSizer121->Add( bSizer125, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); + + wxBoxSizer* bSizer126; + bSizer126 = new wxBoxSizer( wxHORIZONTAL ); + + m_bitmapDifferent = new wxStaticBitmap( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 48,48 ), 0 ); + m_bitmapDifferent->SetToolTip( _("Files that exist on both sides and have different content") ); + + bSizer126->Add( m_bitmapDifferent, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer126->Add( 5, 0, 0, 0, 5 ); + + m_bpButtonDifferent = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 42,42 ), wxBU_AUTODRAW ); + bSizer126->Add( m_bpButtonDifferent, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); + + bSizer121->Add( bSizer126, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); + + sbSizer6->Add( bSizer121, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); bSizer181->Add( sbSizer6, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); @@ -1773,8 +1878,6 @@ SyncDlgGenerated::SyncDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr // Connect Events this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( SyncDlgGenerated::OnClose ) ); - m_button18->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnStartSync ), NULL, this ); - m_checkBoxUseRecycler->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnSelectRecycleBin ), NULL, this ); m_radioBtn1->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( SyncDlgGenerated::OnSyncLeftToRight ), NULL, this ); m_buttonOneWay->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnSyncLeftToRight ), NULL, this ); m_radioBtnUpdate->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( SyncDlgGenerated::OnSyncUpdate ), NULL, this ); @@ -1782,21 +1885,20 @@ SyncDlgGenerated::SyncDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr m_radioBtn2->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( SyncDlgGenerated::OnSyncBothSides ), NULL, this ); m_buttonTwoWay->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnSyncBothSides ), NULL, this ); m_radioBtn3->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( SyncDlgGenerated::OnSyncCostum ), NULL, this ); - m_button6->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnBack ), NULL, this ); + m_checkBoxUseRecycler->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnSelectRecycleBin ), NULL, this ); + m_button6->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnApply ), NULL, this ); m_button16->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnCancel ), NULL, this ); - m_bpButton5->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnExLeftSideOnly ), NULL, this ); - m_bpButton6->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnExRightSideOnly ), NULL, this ); - m_bpButton7->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnLeftNewer ), NULL, this ); - m_bpButton8->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnRightNewer ), NULL, this ); - m_bpButton9->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnDifferent ), NULL, this ); + m_bpButtonLeftOnly->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnExLeftSideOnly ), NULL, this ); + m_bpButtonRightOnly->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnExRightSideOnly ), NULL, this ); + m_bpButtonLeftNewer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnLeftNewer ), NULL, this ); + m_bpButtonRightNewer->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnRightNewer ), NULL, this ); + m_bpButtonDifferent->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnDifferent ), NULL, this ); } SyncDlgGenerated::~SyncDlgGenerated() { // Disconnect Events this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( SyncDlgGenerated::OnClose ) ); - m_button18->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnStartSync ), NULL, this ); - m_checkBoxUseRecycler->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnSelectRecycleBin ), NULL, this ); m_radioBtn1->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( SyncDlgGenerated::OnSyncLeftToRight ), NULL, this ); m_buttonOneWay->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnSyncLeftToRight ), NULL, this ); m_radioBtnUpdate->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( SyncDlgGenerated::OnSyncUpdate ), NULL, this ); @@ -1804,13 +1906,14 @@ SyncDlgGenerated::~SyncDlgGenerated() m_radioBtn2->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( SyncDlgGenerated::OnSyncBothSides ), NULL, this ); m_buttonTwoWay->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnSyncBothSides ), NULL, this ); m_radioBtn3->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( SyncDlgGenerated::OnSyncCostum ), NULL, this ); - m_button6->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnBack ), NULL, this ); + m_checkBoxUseRecycler->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnSelectRecycleBin ), NULL, this ); + m_button6->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnApply ), NULL, this ); m_button16->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnCancel ), NULL, this ); - m_bpButton5->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnExLeftSideOnly ), NULL, this ); - m_bpButton6->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnExRightSideOnly ), NULL, this ); - m_bpButton7->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnLeftNewer ), NULL, this ); - m_bpButton8->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnRightNewer ), NULL, this ); - m_bpButton9->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnDifferent ), NULL, this ); + m_bpButtonLeftOnly->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnExLeftSideOnly ), NULL, this ); + m_bpButtonRightOnly->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnExRightSideOnly ), NULL, this ); + m_bpButtonLeftNewer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnLeftNewer ), NULL, this ); + m_bpButtonRightNewer->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnRightNewer ), NULL, this ); + m_bpButtonDifferent->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( SyncDlgGenerated::OnDifferent ), NULL, this ); } SyncStatusDlgGenerated::SyncStatusDlgGenerated( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style ) @@ -2112,10 +2215,6 @@ HelpDlgGenerated::HelpDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr m_staticText77->Wrap( -1 ); bSizer70->Add( m_staticText77, 0, wxRIGHT|wxLEFT, 5 ); - m_staticText78 = new wxStaticText( m_scrolledWindow1, wxID_ANY, _("- different (same date, different size)"), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText78->Wrap( -1 ); - bSizer70->Add( m_staticText78, 0, wxRIGHT|wxLEFT, 5 ); - m_staticText79 = new wxStaticText( m_scrolledWindow1, wxID_ANY, _("- exists left only"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText79->Wrap( -1 ); bSizer70->Add( m_staticText79, 0, wxRIGHT|wxLEFT, 5 ); @@ -2124,6 +2223,13 @@ HelpDlgGenerated::HelpDlgGenerated( wxWindow* parent, wxWindowID id, const wxStr m_staticText80->Wrap( -1 ); bSizer70->Add( m_staticText80, 0, wxRIGHT|wxLEFT, 5 ); + + bSizer70->Add( 0, 10, 0, 0, 5 ); + + m_staticText78 = new wxStaticText( m_scrolledWindow1, wxID_ANY, _("- conflict"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText78->Wrap( -1 ); + bSizer70->Add( m_staticText78, 0, wxRIGHT|wxLEFT, 5 ); + m_scrolledWindow1->SetSizer( bSizer70 ); m_scrolledWindow1->Layout(); bSizer70->Fit( m_scrolledWindow1 ); @@ -2878,7 +2984,7 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w wxBoxSizer* bSizer70; bSizer70 = new wxBoxSizer( wxHORIZONTAL ); - m_staticText44 = new wxStaticText( this, wxID_ANY, _("Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the full name including path prefix."), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText44 = new wxStaticText( this, wxID_ANY, _("Only files/directories that pass filtering will be selected for synchronization. The filter will be applied to the name relative(!) to the synchronization directories."), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText44->Wrap( 400 ); bSizer70->Add( m_staticText44, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5 ); @@ -2910,7 +3016,7 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w bSizer52->Add( m_staticText45, 0, wxBOTTOM, 5 ); - m_staticText83 = new wxStaticText( m_panel13, wxID_ANY, _("1. Enter full file or directory names separated by ';' or a new line."), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText83 = new wxStaticText( m_panel13, wxID_ANY, _("1. Enter relative file or directory names separated by ';' or a new line."), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText83->Wrap( -1 ); bSizer52->Add( m_staticText83, 0, 0, 5 ); @@ -2922,10 +3028,6 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w m_staticText85->Wrap( -1 ); bSizer52->Add( m_staticText85, 0, 0, 5 ); - m_staticText86 = new wxStaticText( m_panel13, wxID_ANY, _("4. Keep the number of (different) entries small for best performance."), wxDefaultPosition, wxDefaultSize, 0 ); - m_staticText86->Wrap( -1 ); - bSizer52->Add( m_staticText86, 0, wxBOTTOM, 5 ); - bSizer69->Add( bSizer52, 0, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT, 10 ); wxStaticBoxSizer* sbSizer21; @@ -2934,11 +3036,11 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w wxBoxSizer* bSizer66; bSizer66 = new wxBoxSizer( wxHORIZONTAL ); - m_staticText181 = new wxStaticText( m_panel13, wxID_ANY, _("Include: *.doc;*.zip;*.exe\nExclude: *\\temp\\*"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText181 = new wxStaticText( m_panel13, wxID_ANY, _("Include: *.doc;*.zip;*.exe\nExclude: \\temp\\*"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText181->Wrap( -1 ); bSizer66->Add( m_staticText181, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 5 ); - m_staticText1811 = new wxStaticText( m_panel13, wxID_ANY, _("Synchronize all .doc, .zip and .exe files except everything from folder \"temp\"."), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText1811 = new wxStaticText( m_panel13, wxID_ANY, _("Synchronize all .doc, .zip and .exe files except everything in subfolder \"temp\"."), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText1811->Wrap( 250 ); m_staticText1811->SetFont( wxFont( 8, 74, 93, 90, false, wxT("Tahoma") ) ); @@ -2978,7 +3080,7 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w m_textCtrlInclude = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE ); fgSizer3->Add( m_textCtrlInclude, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); - sbSizer8->Add( fgSizer3, 0, wxEXPAND, 5 ); + sbSizer8->Add( fgSizer3, 1, wxEXPAND, 5 ); wxFlexGridSizer* fgSizer4; fgSizer4 = new wxFlexGridSizer( 2, 2, 0, 0 ); @@ -3002,7 +3104,7 @@ FilterDlgGenerated::FilterDlgGenerated( wxWindow* parent, wxWindowID id, const w m_textCtrlExclude = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,-1 ), wxTE_MULTILINE ); fgSizer4->Add( m_textCtrlExclude, 1, wxALL|wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 ); - sbSizer8->Add( fgSizer4, 0, wxEXPAND, 5 ); + sbSizer8->Add( fgSizer4, 1, wxEXPAND, 5 ); bSizer21->Add( sbSizer8, 1, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT|wxEXPAND, 5 ); @@ -3090,6 +3192,10 @@ CustomizeColsDlgGenerated::CustomizeColsDlgGenerated( wxWindow* parent, wxWindow bSizer96->Add( bSizer99, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); + m_checkBoxShowFileIcons = new wxCheckBox( this, wxID_ANY, _("Show file icons"), wxDefaultPosition, wxDefaultSize, 0 ); + + bSizer96->Add( m_checkBoxShowFileIcons, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP|wxBOTTOM, 5 ); + wxBoxSizer* bSizer97; bSizer97 = new wxBoxSizer( wxHORIZONTAL ); @@ -3111,9 +3217,6 @@ CustomizeColsDlgGenerated::CustomizeColsDlgGenerated( wxWindow* parent, wxWindow bSizer96->Add( bSizer97, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); - - bSizer96->Add( 0, 0, 0, wxALIGN_CENTER_HORIZONTAL, 20 ); - this->SetSizer( bSizer96 ); this->Layout(); bSizer96->Fit( this ); @@ -3184,20 +3287,39 @@ GlobalSettingsDlgGenerated::GlobalSettingsDlgGenerated( wxWindow* parent, wxWind m_staticText99 = new wxStaticText( this, wxID_ANY, _("File Time tolerance (seconds):"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText99->Wrap( -1 ); + m_staticText99->Hide(); m_staticText99->SetToolTip( _("File times that differ by up to the specified number of seconds are still handled as having same time.") ); bSizer100->Add( m_staticText99, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); - - bSizer100->Add( 0, 0, 1, wxEXPAND, 5 ); - m_spinCtrlFileTimeTolerance = new wxSpinCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS|wxSP_WRAP, 0, 2000000000, 0 ); + m_spinCtrlFileTimeTolerance->Hide(); m_spinCtrlFileTimeTolerance->SetToolTip( _("File times that differ by up to the specified number of seconds are still handled as having same time.") ); bSizer100->Add( m_spinCtrlFileTimeTolerance, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); sbSizer23->Add( bSizer100, 1, wxEXPAND, 5 ); + wxBoxSizer* bSizer120; + bSizer120 = new wxBoxSizer( wxHORIZONTAL ); + + m_staticText114 = new wxStaticText( this, wxID_ANY, _("Ignore 1-hour file time difference"), wxDefaultPosition, wxDefaultSize, 0 ); + m_staticText114->Wrap( -1 ); + m_staticText114->SetToolTip( _("Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes.") ); + + bSizer120->Add( m_staticText114, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer120->Add( 0, 0, 1, wxEXPAND, 5 ); + + m_checkBoxIgnoreOneHour = new wxCheckBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); + + m_checkBoxIgnoreOneHour->SetToolTip( _("Treat file times that differ by exactly +/- 1 hour as equal, less than 1 hour as conflict in order to handle Daylight Saving Time changes.") ); + + bSizer120->Add( m_checkBoxIgnoreOneHour, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 ); + + sbSizer23->Add( bSizer120, 1, wxEXPAND, 5 ); + m_staticline10 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL ); sbSizer23->Add( m_staticline10, 0, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxTOP|wxBOTTOM, 5 ); @@ -3232,7 +3354,7 @@ GlobalSettingsDlgGenerated::GlobalSettingsDlgGenerated( wxWindow* parent, wxWind m_buttonResetWarnings = new wxButtonWithImage( this, wxID_ANY, _("Reset"), wxDefaultPosition, wxSize( 80,-1 ), 0 ); m_buttonResetWarnings->SetFont( wxFont( 8, 74, 90, 92, false, wxT("Tahoma") ) ); - m_buttonResetWarnings->SetToolTip( _("Resets all warning messages") ); + m_buttonResetWarnings->SetToolTip( _("Reset all warning messages") ); bSizer101->Add( m_buttonResetWarnings, 0, wxALIGN_CENTER_HORIZONTAL|wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); diff --git a/ui/guiGenerated.h b/ui/guiGenerated.h index 4bf190e1..37d41205 100644 --- a/ui/guiGenerated.h +++ b/ui/guiGenerated.h @@ -38,10 +38,10 @@ class wxButtonWithImage; #include <wx/scrolwin.h> #include <wx/grid.h> #include <wx/choice.h> +#include <wx/textctrl.h> #include <wx/stattext.h> #include <wx/statline.h> #include <wx/frame.h> -#include <wx/textctrl.h> #include <wx/notebook.h> #include <wx/dialog.h> #include <wx/gauge.h> @@ -65,6 +65,7 @@ class MainDialogGenerated : public wxFrame wxMenu* m_menuFile; wxMenuItem* m_menuItem10; wxMenuItem* m_menuItem11; + wxMenuItem* m_menuItemSwitchView; wxMenu* m_menuAdvanced; wxMenu* m_menuLanguages; wxMenuItem* m_menuItemGerman; @@ -99,7 +100,9 @@ class MainDialogGenerated : public wxFrame wxHyperlinkCtrl* m_hyperlinkCfgFilter; wxCheckBox* m_checkBoxHideFilt; - wxButtonWithImage* m_buttonSync; + + wxBitmapButton* m_bpButtonSyncConfig; + wxButtonWithImage* m_buttonStartSync; wxPanel* m_panelTopLeft; wxStaticBoxSizer* sbSizer2; @@ -108,7 +111,7 @@ class MainDialogGenerated : public wxFrame wxPanel* m_panelTopMiddle; wxBoxSizer* bSizerMiddle; - wxBitmapButton* m_bpButtonSwap; + wxBitmapButton* m_bpButtonSwitchView; wxPanel* m_panelTopRight; @@ -126,11 +129,9 @@ class MainDialogGenerated : public wxFrame wxPanel* m_panelRight; CustomGridRight* m_gridRight; wxBoxSizer* bSizer3; - wxBoxSizer* bSizer58; wxBitmapButton* m_bpButtonSave; wxBitmapButton* m_bpButtonLoad; wxChoice* m_choiceHistory; - wxPanel* m_panel112; wxBitmapButton* m_bpButtonLeftOnly; @@ -139,7 +140,21 @@ class MainDialogGenerated : public wxFrame wxBitmapButton* m_bpButtonDifferent; wxBitmapButton* m_bpButtonRightNewer; wxBitmapButton* m_bpButtonRightOnly; + wxBitmapButton* m_bpButtonSyncDirLeft; + wxBitmapButton* m_bpButtonSyncDirNone; + wxBitmapButton* m_bpButtonSyncDirRight; + wxBitmapButton* m_bpButtonConflict; + + wxPanel* m_panelSyncPreview; + wxStaticBitmap* m_bitmapCreate; + wxTextCtrl* m_textCtrlCreate; + wxStaticBitmap* m_bitmapDelete; + wxTextCtrl* m_textCtrlDelete; + wxStaticBitmap* m_bitmapUpdate; + wxTextCtrl* m_textCtrlUpdate; + wxStaticBitmap* m_bitmapData; + wxTextCtrl* m_textCtrlData; wxBitmapButton* m_bpButton10; wxPanel* m_panel7; @@ -158,7 +173,8 @@ class MainDialogGenerated : public wxFrame // Virtual event handlers, overide them in your derived class virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } virtual void OnCompare( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSync( wxCommandEvent& event ){ event.Skip(); } + virtual void OnStartSync( wxCommandEvent& event ){ event.Skip(); } + virtual void OnSwitchView( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuSaveConfig( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuLoadConfig( wxCommandEvent& event ){ event.Skip(); } virtual void OnMenuQuit( wxCommandEvent& event ){ event.Skip(); } @@ -187,9 +203,9 @@ class MainDialogGenerated : public wxFrame virtual void OnFilterButton( wxCommandEvent& event ){ event.Skip(); } virtual void OnConfigureFilter( wxHyperlinkEvent& event ){ event.Skip(); } virtual void OnHideFilteredButton( wxCommandEvent& event ){ event.Skip(); } + virtual void OnSyncSettings( wxCommandEvent& event ){ event.Skip(); } virtual void OnFolderHistoryKeyEvent( wxKeyEvent& event ){ event.Skip(); } virtual void OnDirSelected( wxFileDirPickerEvent& event ){ event.Skip(); } - virtual void OnSwapDirs( wxCommandEvent& event ){ event.Skip(); } virtual void OnAddFolderPair( wxCommandEvent& event ){ event.Skip(); } virtual void OnLeftGridDoubleClick( wxGridEvent& event ){ event.Skip(); } virtual void OnContextMenu( wxGridEvent& event ){ event.Skip(); } @@ -210,6 +226,10 @@ class MainDialogGenerated : public wxFrame virtual void OnDifferentFiles( wxCommandEvent& event ){ event.Skip(); } virtual void OnRightNewerFiles( wxCommandEvent& event ){ event.Skip(); } virtual void OnRightOnlyFiles( wxCommandEvent& event ){ event.Skip(); } + virtual void OnSyncDirLeft( wxCommandEvent& event ){ event.Skip(); } + virtual void OnSyncDirNone( wxCommandEvent& event ){ event.Skip(); } + virtual void OnSyncDirRight( wxCommandEvent& event ){ event.Skip(); } + virtual void OnConflictFiles( wxCommandEvent& event ){ event.Skip(); } virtual void OnQuit( wxCommandEvent& event ){ event.Skip(); } @@ -304,19 +324,24 @@ class BatchDlgGenerated : public wxDialog - wxStaticText* m_staticText211; - wxStaticText* m_staticText311; + wxStaticText* m_staticText21; + wxStaticText* m_staticText31; wxStaticLine* m_staticline3; - wxStaticBitmap* m_bitmap13; - wxBitmapButton* m_bpButton5; - wxStaticBitmap* m_bitmap14; - wxBitmapButton* m_bpButton6; - wxStaticBitmap* m_bitmap15; - wxBitmapButton* m_bpButton7; - wxStaticBitmap* m_bitmap16; - wxBitmapButton* m_bpButton8; - wxStaticBitmap* m_bitmap17; - wxBitmapButton* m_bpButton9; + wxStaticBitmap* m_bitmapLeftOnly; + + wxBitmapButton* m_bpButtonLeftOnly; + wxStaticBitmap* m_bitmapRightOnly; + + wxBitmapButton* m_bpButtonRightOnly; + wxStaticBitmap* m_bitmapLeftNewer; + + wxBitmapButton* m_bpButtonLeftNewer; + wxStaticBitmap* m_bitmapRightNewer; + + wxBitmapButton* m_bpButtonRightNewer; + wxStaticBitmap* m_bitmapDifferent; + + wxBitmapButton* m_bpButtonDifferent; wxPanel* m_panelFilter; wxStaticText* m_staticText15; @@ -399,12 +424,6 @@ class SyncDlgGenerated : public wxDialog private: protected: - wxBoxSizer* bSizer201; - wxButtonWithImage* m_button18; - - wxCheckBox* m_checkBoxUseRecycler; - wxCheckBox* m_checkBoxIgnoreErrors; - wxStaticText* m_staticText1; wxRadioButton* m_radioBtn1; wxButton* m_buttonOneWay; @@ -421,41 +440,41 @@ class SyncDlgGenerated : public wxDialog wxStaticText* m_staticText9; + wxBoxSizer* bSizer201; + wxCheckBox* m_checkBoxUseRecycler; + wxCheckBox* m_checkBoxIgnoreErrors; + wxButton* m_button6; wxButton* m_button16; - wxStaticText* m_staticText37; - wxTextCtrl* m_textCtrlCreate; - wxStaticText* m_staticText14; - wxTextCtrl* m_textCtrlDelete; - wxStaticText* m_staticText42; - wxTextCtrl* m_textCtrlUpdate; - wxStaticText* m_staticText43; - wxTextCtrl* m_textCtrlData; wxStaticText* m_staticText21; wxStaticText* m_staticText31; wxStaticLine* m_staticline3; - wxStaticBitmap* m_bitmap13; - wxBitmapButton* m_bpButton5; - wxStaticBitmap* m_bitmap14; - wxBitmapButton* m_bpButton6; - wxStaticBitmap* m_bitmap15; - wxBitmapButton* m_bpButton7; - wxStaticBitmap* m_bitmap16; - wxBitmapButton* m_bpButton8; - wxStaticBitmap* m_bitmap17; - wxBitmapButton* m_bpButton9; + wxStaticBitmap* m_bitmapLeftOnly; + + wxBitmapButton* m_bpButtonLeftOnly; + wxStaticBitmap* m_bitmapRightOnly; + + wxBitmapButton* m_bpButtonRightOnly; + wxStaticBitmap* m_bitmapLeftNewer; + + wxBitmapButton* m_bpButtonLeftNewer; + wxStaticBitmap* m_bitmapRightNewer; + + wxBitmapButton* m_bpButtonRightNewer; + wxStaticBitmap* m_bitmapDifferent; + + wxBitmapButton* m_bpButtonDifferent; // Virtual event handlers, overide them in your derived class virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } - virtual void OnStartSync( wxCommandEvent& event ){ event.Skip(); } - virtual void OnSelectRecycleBin( wxCommandEvent& event ){ event.Skip(); } virtual void OnSyncLeftToRight( wxCommandEvent& event ){ event.Skip(); } virtual void OnSyncUpdate( wxCommandEvent& event ){ event.Skip(); } virtual void OnSyncBothSides( wxCommandEvent& event ){ event.Skip(); } virtual void OnSyncCostum( wxCommandEvent& event ){ event.Skip(); } - virtual void OnBack( wxCommandEvent& event ){ event.Skip(); } + virtual void OnSelectRecycleBin( wxCommandEvent& event ){ event.Skip(); } + virtual void OnApply( wxCommandEvent& event ){ event.Skip(); } virtual void OnCancel( wxCommandEvent& event ){ event.Skip(); } virtual void OnExLeftSideOnly( wxCommandEvent& event ){ event.Skip(); } virtual void OnExRightSideOnly( wxCommandEvent& event ){ event.Skip(); } @@ -549,9 +568,10 @@ class HelpDlgGenerated : public wxDialog wxStaticText* m_staticText75; wxStaticText* m_staticText76; wxStaticText* m_staticText77; - wxStaticText* m_staticText78; wxStaticText* m_staticText79; wxStaticText* m_staticText80; + + wxStaticText* m_staticText78; wxScrolledWindow* m_scrolledWindow5; wxStaticText* m_staticText65; wxStaticText* m_staticText66; @@ -804,7 +824,6 @@ class FilterDlgGenerated : public wxDialog wxStaticText* m_staticText83; wxStaticText* m_staticText84; wxStaticText* m_staticText85; - wxStaticText* m_staticText86; wxStaticText* m_staticText181; wxStaticText* m_staticText1811; @@ -846,11 +865,11 @@ class CustomizeColsDlgGenerated : public wxDialog wxCheckListBox* m_checkListColumns; wxBitmapButton* m_bpButton29; wxBitmapButton* m_bpButton30; + wxCheckBox* m_checkBoxShowFileIcons; wxButton* m_button28; wxButton* m_button9; wxButton* m_button29; - // Virtual event handlers, overide them in your derived class virtual void OnClose( wxCloseEvent& event ){ event.Skip(); } virtual void OnMoveUp( wxCommandEvent& event ){ event.Skip(); } @@ -880,8 +899,10 @@ class GlobalSettingsDlgGenerated : public wxDialog wxStaticText* m_staticText99; - wxSpinCtrl* m_spinCtrlFileTimeTolerance; + wxStaticText* m_staticText114; + + wxCheckBox* m_checkBoxIgnoreOneHour; wxStaticLine* m_staticline10; wxStaticText* m_staticText97; wxTextCtrl* m_textCtrlFileManager; diff --git a/ui/guiStatusHandler.cpp b/ui/guiStatusHandler.cpp index 74205dba..c2f27fac 100644 --- a/ui/guiStatusHandler.cpp +++ b/ui/guiStatusHandler.cpp @@ -17,10 +17,11 @@ CompareStatusHandler::CompareStatusHandler(MainDialog* dlg) : mainDialog->m_bpButtonFilter->Disable(); mainDialog->m_hyperlinkCfgFilter->Disable(); mainDialog->m_checkBoxHideFilt->Disable(); - mainDialog->m_buttonSync->Disable(); + mainDialog->m_bpButtonSyncConfig->Disable(); + mainDialog->m_buttonStartSync->Disable(); mainDialog->m_dirPickerLeft->Disable(); mainDialog->m_dirPickerRight->Disable(); - mainDialog->m_bpButtonSwap->Disable(); + mainDialog->m_bpButtonSwitchView->Disable(); mainDialog->m_bpButtonLeftOnly->Disable(); mainDialog->m_bpButtonLeftNewer->Disable(); mainDialog->m_bpButtonEqual->Disable(); @@ -70,10 +71,11 @@ CompareStatusHandler::~CompareStatusHandler() mainDialog->m_bpButtonFilter->Enable(); mainDialog->m_hyperlinkCfgFilter->Enable(); mainDialog->m_checkBoxHideFilt->Enable(); - mainDialog->m_buttonSync->Enable(); + mainDialog->m_bpButtonSyncConfig->Enable(); + mainDialog->m_buttonStartSync->Enable(); mainDialog->m_dirPickerLeft->Enable(); mainDialog->m_dirPickerRight->Enable(); - mainDialog->m_bpButtonSwap->Enable(); + mainDialog->m_bpButtonSwitchView->Enable(); mainDialog->m_bpButtonLeftOnly->Enable(); mainDialog->m_bpButtonLeftNewer->Enable(); mainDialog->m_bpButtonEqual->Enable(); @@ -96,7 +98,7 @@ CompareStatusHandler::~CompareStatusHandler() mainDialog->m_menubar1->EnableTop(1, true); mainDialog->m_menubar1->EnableTop(2, true); - if (abortRequested) + if (abortIsRequested()) mainDialog->pushStatusInformation(_("Operation aborted!")); mainDialog->m_buttonAbort->Disable(); @@ -125,26 +127,38 @@ void CompareStatusHandler::initNewProcess(int objectsTotal, wxLongLong dataTotal { currentProcess = processID; - if (currentProcess == StatusHandler::PROCESS_SCANNING) - ; - else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT) + switch (currentProcess) { + case StatusHandler::PROCESS_SCANNING: + break; + case StatusHandler::PROCESS_COMPARING_CONTENT: mainDialog->compareStatus->switchToCompareBytewise(objectsTotal, dataTotal); mainDialog->Layout(); + break; + case StatusHandler::PROCESS_SYNCHRONIZING: + case StatusHandler::PROCESS_NONE: + assert(false); + break; } - - else assert(false); } inline void CompareStatusHandler::updateProcessedData(int objectsProcessed, wxLongLong dataProcessed) { - if (currentProcess == StatusHandler::PROCESS_SCANNING) + switch (currentProcess) + { + case StatusHandler::PROCESS_SCANNING: mainDialog->compareStatus->incScannedObjects_NoUpdate(objectsProcessed); - else if (currentProcess == StatusHandler::PROCESS_COMPARING_CONTENT) + break; + case StatusHandler::PROCESS_COMPARING_CONTENT: mainDialog->compareStatus->incProcessedCmpData_NoUpdate(objectsProcessed, dataProcessed); - else assert(false); + break; + case StatusHandler::PROCESS_SYNCHRONIZING: + case StatusHandler::PROCESS_NONE: + assert(false); + break; + } } @@ -228,7 +242,7 @@ void CompareStatusHandler::forceUiRefresh() void CompareStatusHandler::abortThisProcess() { - abortRequested = true; + requestAbortion(); throw FreeFileSync::AbortThisProcess(); //abort can be triggered by syncStatusFrame } //######################################################################################################## @@ -266,7 +280,7 @@ SyncStatusHandler::~SyncStatusHandler() } //notify to syncStatusFrame that current process has ended - if (abortRequested) + if (abortIsRequested()) { result+= wxString(_("Synchronization aborted!")) + wxT(" ") + _("You may try to synchronize remaining items again (WITHOUT having to re-compare)!"); syncStatusFrame->setStatusText_NoUpdate(result.c_str()); @@ -296,10 +310,18 @@ void SyncStatusHandler::updateStatusText(const Zstring& text) void SyncStatusHandler::initNewProcess(int objectsTotal, wxLongLong dataTotal, Process processID) { - assert (processID == StatusHandler::PROCESS_SYNCHRONIZING); - - syncStatusFrame->resetGauge(objectsTotal, dataTotal); - syncStatusFrame->setCurrentStatus(SyncStatus::SYNCHRONIZING); + switch (processID) + { + case StatusHandler::PROCESS_SYNCHRONIZING: + syncStatusFrame->resetGauge(objectsTotal, dataTotal); + syncStatusFrame->setCurrentStatus(SyncStatus::SYNCHRONIZING); + break; + case StatusHandler::PROCESS_SCANNING: + case StatusHandler::PROCESS_COMPARING_CONTENT: + case StatusHandler::PROCESS_NONE: + assert(false); + break; + } } @@ -397,6 +419,6 @@ void SyncStatusHandler::forceUiRefresh() void SyncStatusHandler::abortThisProcess() { - abortRequested = true; + requestAbortion(); throw FreeFileSync::AbortThisProcess(); //abort can be triggered by syncStatusFrame } diff --git a/ui/sorting.h b/ui/sorting.h index 22b9c39b..f7879a8b 100644 --- a/ui/sorting.h +++ b/ui/sorting.h @@ -291,13 +291,13 @@ namespace FreeFileSync const Zstring* const dirNameB = side == SORT_ON_LEFT ? &b.syncPair.leftDirectory : &b.syncPair.rightDirectory; #ifdef FFS_WIN //case-insensitive comparison! - return sortAscending == ASCENDING ? - FreeFileSync::compareStringsWin32(dirNameA->c_str(), dirNameB->c_str()) < 0 : //way faster than wxString::CmpNoCase() in windows build!!! - FreeFileSync::compareStringsWin32(dirNameA->c_str(), dirNameB->c_str()) > 0; + return sortAscending == ASCENDING ? + FreeFileSync::compareStringsWin32(dirNameA->c_str(), dirNameB->c_str()) < 0 : //way faster than wxString::CmpNoCase() in windows build!!! + FreeFileSync::compareStringsWin32(dirNameA->c_str(), dirNameB->c_str()) > 0; #elif defined FFS_LINUX - return sortAscending == ASCENDING ? - dirNameA->Cmp(*dirNameB) < 0 : - dirNameA->Cmp(*dirNameB) > 0; + return sortAscending == ASCENDING ? + dirNameA->Cmp(*dirNameB) < 0 : + dirNameA->Cmp(*dirNameB) > 0; #endif } } diff --git a/version/version.h b/version/version.h index a0ec5908..41c73ce9 100644 --- a/version/version.h +++ b/version/version.h @@ -2,5 +2,5 @@ namespace FreeFileSync { - static const wxString currentVersion = wxT("1.18"); //internal linkage! + static const wxString currentVersion = wxT("1.19"); //internal linkage! } |