diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:00:17 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:00:17 +0200 |
commit | fd0853d2623dd278b08288331ed42e3be59252fb (patch) | |
tree | a7645daeaef8bdbed064faf4eb88e72cee58726c /library | |
parent | 2.1 (diff) | |
download | FreeFileSync-fd0853d2623dd278b08288331ed42e3be59252fb.tar.gz FreeFileSync-fd0853d2623dd278b08288331ed42e3be59252fb.tar.bz2 FreeFileSync-fd0853d2623dd278b08288331ed42e3be59252fb.zip |
2.2
Diffstat (limited to 'library')
-rw-r--r-- | library/CustomGrid.cpp | 287 | ||||
-rw-r--r-- | library/CustomGrid.h | 16 | ||||
-rw-r--r-- | library/errorLogging.cpp | 48 | ||||
-rw-r--r-- | library/errorLogging.h | 43 | ||||
-rw-r--r-- | library/filter.cpp | 16 | ||||
-rw-r--r-- | library/filter.h | 3 | ||||
-rw-r--r-- | library/iconBuffer.cpp | 132 | ||||
-rw-r--r-- | library/iconBuffer.h | 4 | ||||
-rw-r--r-- | library/pch.h | 3 | ||||
-rw-r--r-- | library/processXml.cpp | 1073 | ||||
-rw-r--r-- | library/processXml.h | 54 | ||||
-rw-r--r-- | library/resources.cpp | 44 | ||||
-rw-r--r-- | library/resources.h | 14 | ||||
-rw-r--r-- | library/statistics.cpp | 3 | ||||
-rw-r--r-- | library/statusHandler.h | 6 |
15 files changed, 793 insertions, 953 deletions
diff --git a/library/CustomGrid.cpp b/library/CustomGrid.cpp index 591230e2..4cb82961 100644 --- a/library/CustomGrid.cpp +++ b/library/CustomGrid.cpp @@ -1,5 +1,5 @@ #include "customGrid.h" -#include "globalFunctions.h" +#include "../shared/globalFunctions.h" #include "resources.h" #include <wx/dc.h> #include "../algorithm.h" @@ -7,6 +7,7 @@ #include <typeinfo> #include "../ui/gridView.h" #include "../synchronization.h" +#include "../shared/customTooltip.h" #ifdef FFS_WIN #include <wx/timer.h> @@ -60,9 +61,9 @@ public: virtual ~CustomGridTable() {} - void setGridDataTable(const GridView* gridDataView) + void setGridDataTable(const GridView* view) { - this->gridDataView = gridDataView; + this->gridDataView = view; } @@ -275,15 +276,15 @@ public: switch (getTypeAtPos(col)) { case xmlAccess::FULL_PATH: - return wxString(gridLine->fileDescrLeft.fullName.c_str()).BeforeLast(FreeFileSync::FILE_NAME_SEPARATOR); + return wxString(gridLine->fileDescrLeft.fullName.c_str()).BeforeLast(globalFunctions::FILE_NAME_SEPARATOR); case xmlAccess::FILENAME: //filename - return wxString(gridLine->fileDescrLeft.relativeName.c_str()).AfterLast(FreeFileSync::FILE_NAME_SEPARATOR); + return wxString(gridLine->fileDescrLeft.relativeName.c_str()).AfterLast(globalFunctions::FILE_NAME_SEPARATOR); case xmlAccess::REL_PATH: //relative path - return wxString(gridLine->fileDescrLeft.relativeName.c_str()).BeforeLast(FreeFileSync::FILE_NAME_SEPARATOR); + return wxString(gridLine->fileDescrLeft.relativeName.c_str()).BeforeLast(globalFunctions::FILE_NAME_SEPARATOR); case xmlAccess::DIRECTORY: return gridDataView->getFolderPair(row).leftDirectory.c_str(); case xmlAccess::SIZE: //file size - return globalFunctions::includeNumberSeparator(gridLine->fileDescrLeft.fileSize.ToString()); + return FreeFileSync::includeNumberSeparator(gridLine->fileDescrLeft.fileSize.ToString()); case xmlAccess::DATE: //date return FreeFileSync::utcTimeToLocalString(gridLine->fileDescrLeft.lastWriteTimeRaw, gridLine->fileDescrLeft.fullName); } @@ -355,15 +356,15 @@ public: switch (getTypeAtPos(col)) { case xmlAccess::FULL_PATH: - return wxString(gridLine->fileDescrRight.fullName.c_str()).BeforeLast(FreeFileSync::FILE_NAME_SEPARATOR); + return wxString(gridLine->fileDescrRight.fullName.c_str()).BeforeLast(globalFunctions::FILE_NAME_SEPARATOR); case xmlAccess::FILENAME: //filename - return wxString(gridLine->fileDescrRight.relativeName.c_str()).AfterLast(FreeFileSync::FILE_NAME_SEPARATOR); + return wxString(gridLine->fileDescrRight.relativeName.c_str()).AfterLast(globalFunctions::FILE_NAME_SEPARATOR); case xmlAccess::REL_PATH: //relative path - return wxString(gridLine->fileDescrRight.relativeName.c_str()).BeforeLast(FreeFileSync::FILE_NAME_SEPARATOR); + return wxString(gridLine->fileDescrRight.relativeName.c_str()).BeforeLast(globalFunctions::FILE_NAME_SEPARATOR); case xmlAccess::DIRECTORY: return gridDataView->getFolderPair(row).rightDirectory.c_str(); case xmlAccess::SIZE: //file size - return globalFunctions::includeNumberSeparator(gridLine->fileDescrRight.fileSize.ToString()); + return FreeFileSync::includeNumberSeparator(gridLine->fileDescrRight.fileSize.ToString()); case xmlAccess::DATE: //date return FreeFileSync::utcTimeToLocalString(gridLine->fileDescrRight.lastWriteTimeRaw, gridLine->fileDescrRight.fullName); } @@ -449,7 +450,7 @@ private: if (syncPreviewActive) //synchronization preview { - switch (gridLine->direction) + switch (gridLine->syncDir) { case SYNC_DIR_LEFT: return COLOR_SYNC_BLUE; @@ -904,77 +905,98 @@ public: { //############## show windows explorer file icons ###################### - if (showFileIcons) //evaluate at compile time + if ( showFileIcons && //evaluate at compile time + m_gridDataTable->getTypeAtPos(col) == xmlAccess::FILENAME) { - if ( m_gridDataTable->getTypeAtPos(col) == xmlAccess::FILENAME && - rect.GetWidth() >= IconBuffer::ICON_SIZE) + if (rect.GetWidth() >= IconBuffer::ICON_SIZE) { + // Partitioning: + // _____________________ + // | 2 pix | icon | rest | + // --------------------- + + //clear area where icon will be placed + wxRect rectShrinked(rect); + rectShrinked.SetWidth(IconBuffer::ICON_SIZE + LEFT_BORDER); //add 2 pixel border + wxGridCellRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected); + + //draw rest + wxRect rest(rect); //unscrolled + rest.x += IconBuffer::ICON_SIZE + LEFT_BORDER; + rest.width -= IconBuffer::ICON_SIZE + LEFT_BORDER; + wxGridCellStringRenderer::Draw(grid, attr, dc, rest, row, col, isSelected); + + //try to draw icon //retrieve grid data const Zstring fileName = m_gridDataTable->getFileName(row); if (!fileName.empty()) { - // Partitioning: - // _____________________ - // | 2 pix | icon | rest | - // --------------------- - - //clear area where icon will be placed - wxRect rectShrinked(rect); - rectShrinked.SetWidth(IconBuffer::ICON_SIZE + 2); //add 2 pixel border - wxGridCellRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected); - - //try to draw icon wxIcon icon; + bool iconDrawnFully = false; const bool iconLoaded = IconBuffer::getInstance().requestIcon(fileName, &icon); //returns false if icon is not in buffer if (iconLoaded) - dc.DrawIcon(icon, rectShrinked.GetX() + 2, rectShrinked.GetY()); + { + dc.DrawIcon(icon, rectShrinked.GetX() + LEFT_BORDER, rectShrinked.GetY()); - //----------------------------------------------------------------------------------------------- - //only mark as successful if icon was drawn fully! - //(attention: when scrolling, rows get partially updated, which can result in the upper half being blank!) + //----------------------------------------------------------------------------------------------- + //only mark as successful if icon was drawn fully! + //(attention: when scrolling, rows get partially updated, which can result in the upper half being blank!) - //rect where icon was placed - wxRect iconRect(rect); //unscrolled - iconRect.x += 2; - iconRect.SetWidth(IconBuffer::ICON_SIZE); + //rect where icon was placed + wxRect iconRect(rect); //unscrolled + iconRect.x += LEFT_BORDER; + iconRect.SetWidth(IconBuffer::ICON_SIZE); - //convert to scrolled coordinates - grid.CalcScrolledPosition(iconRect.x, iconRect.y, &iconRect.x, &iconRect.y); + //convert to scrolled coordinates + grid.CalcScrolledPosition(iconRect.x, iconRect.y, &iconRect.x, &iconRect.y); - bool iconDrawnFully = false; - wxRegionIterator regionsInv(grid.GetGridWindow()->GetUpdateRegion()); - while (regionsInv) - { - if (regionsInv.GetRect().Contains(iconRect)) + wxRegionIterator regionsInv(grid.GetGridWindow()->GetUpdateRegion()); + while (regionsInv) { - iconDrawnFully = true; - break; + if (regionsInv.GetRect().Contains(iconRect)) + { + iconDrawnFully = true; + break; + } + ++regionsInv; } - ++regionsInv; } //----------------------------------------------------------------------------------------------- - - //save status of last icon load -> used for async. icon loading m_loadIconSuccess[row] = iconLoaded && iconDrawnFully; - - //draw rest - wxRect rest(rect); //unscrolled - rest.x += IconBuffer::ICON_SIZE + 2; - rest.width -= IconBuffer::ICON_SIZE + 2; - - wxGridCellStringRenderer::Draw(grid, attr, dc, rest, row, col, isSelected); - return; } } + return; } + //default wxGridCellStringRenderer::Draw(grid, attr, dc, rect, row, col, isSelected); } + + virtual wxSize GetBestSize(wxGrid& grid, //adapt reported width if file icons are shown + wxGridCellAttr& attr, + wxDC& dc, + int row, int col) + { + if ( showFileIcons && //evaluate at compile time + m_gridDataTable->getTypeAtPos(col) == xmlAccess::FILENAME) + { + wxSize rv = wxGridCellStringRenderer::GetBestSize(grid, attr, dc, row, col); + rv.SetWidth(rv.GetWidth() + LEFT_BORDER + IconBuffer::ICON_SIZE); + return rv; + } + + //default + return wxGridCellStringRenderer::GetBestSize(grid, attr, dc, row, col); + } + + private: CustomGridRim::LoadSuccess& m_loadIconSuccess; const CustomGridTableRim* const m_gridDataTable; + + static const int LEFT_BORDER = 2; }; #endif @@ -1268,7 +1290,7 @@ IconUpdater::IconUpdater(CustomGridLeft* leftGrid, CustomGridRight* rightGrid) : m_timer(new wxTimer) //connect timer event for async. icon loading { m_timer->Connect(wxEVT_TIMER, wxEventHandler(IconUpdater::loadIconsAsynchronously), NULL, this); - m_timer->Start(50); //timer interval + m_timer->Start(50); //timer interval in ms } @@ -1280,7 +1302,8 @@ void IconUpdater::loadIconsAsynchronously(wxEvent& event) //loads all (not yet) std::vector<Zstring> newLoad; m_rightGrid->getIconsToBeLoaded(newLoad); - globalFunctions::mergeVectors(iconsLeft, newLoad); + //merge vectors + newLoad.insert(newLoad.end(), iconsLeft.begin(), iconsLeft.end()); FreeFileSync::IconBuffer::getInstance().setWorkload(newLoad); //attention: newLoad is invalidated after this call!!! @@ -1424,7 +1447,8 @@ CustomGridMiddle::CustomGridMiddle(wxWindow *parent, selectionPos(BLOCKPOS_CHECK_BOX), highlightedRow(-1), highlightedPos(BLOCKPOS_CHECK_BOX), - gridDataTable(NULL) + gridDataTable(NULL), + toolTip(new CustomTooltip) { //connect events for dynamic selection of sync direction GetGridWindow()->Connect(wxEVT_MOTION, wxMouseEventHandler(CustomGridMiddle::OnMouseMovement), NULL, this); @@ -1480,6 +1504,9 @@ void CustomGridMiddle::OnMouseMovement(wxMouseEvent& event) if ( highlightedRowOld >= 0 && highlightedRow != highlightedRowOld) RefreshCell(highlightedRowOld, 0); + + //handle tooltip + showToolTip(highlightedRow, GetGridWindow()->ClientToScreen(event.GetPosition())); } event.Skip(); @@ -1491,6 +1518,78 @@ void CustomGridMiddle::OnLeaveWindow(wxMouseEvent& event) highlightedRow = -1; highlightedPos = BLOCKPOS_CHECK_BOX; Refresh(); + + //handle tooltip + toolTip->hide(); +} + + +void CustomGridMiddle::showToolTip(int rowNumber, wxPoint pos) +{ + const FileCompareLine* const rowData = gridDataTable->getRawData(rowNumber); + if (rowData == NULL) //if invalid row... + { + toolTip->hide(); + return; + } + + if (gridDataTable->syncPreviewIsActive()) //synchronization preview + { + switch (getSyncOperation(*rowData)) + { + case SO_CREATE_NEW_LEFT: + toolTip->show(_("Copy from right to left"), pos, GlobalResources::getInstance().bitmapSyncCreateLeftAct); + break; + case SO_CREATE_NEW_RIGHT: + toolTip->show(_("Copy from left to right"), pos, GlobalResources::getInstance().bitmapSyncCreateRightAct); + break; + case SO_DELETE_LEFT: + toolTip->show(_("Delete files/folders existing on left side only"), pos, GlobalResources::getInstance().bitmapSyncDeleteLeftAct); + break; + case SO_DELETE_RIGHT: + toolTip->show(_("Delete files/folders existing on right side only"), pos, GlobalResources::getInstance().bitmapSyncDeleteRightAct); + break; + case SO_OVERWRITE_LEFT: + toolTip->show(_("Copy from right to left overwriting"), pos, GlobalResources::getInstance().bitmapSyncDirLeftAct); + break; + case SO_OVERWRITE_RIGHT: + toolTip->show(_("Copy from left to right overwriting"), pos, GlobalResources::getInstance().bitmapSyncDirRightAct); + break; + case SO_DO_NOTHING: + toolTip->show(_("Do nothing"), pos, GlobalResources::getInstance().bitmapSyncDirNoneAct); + break; + case SO_UNRESOLVED_CONFLICT: + toolTip->show(rowData->conflictDescription.get(), pos, GlobalResources::getInstance().bitmapConflictAct); + break; + }; + } + else + { + switch (rowData->cmpResult) + { + case FILE_LEFT_SIDE_ONLY: + toolTip->show(_("Files/folders that exist on left side only"), pos, GlobalResources::getInstance().bitmapLeftOnlyAct); + break; + case FILE_RIGHT_SIDE_ONLY: + toolTip->show(_("Files/folders that exist on right side only"), pos, GlobalResources::getInstance().bitmapRightOnlyAct); + break; + case FILE_LEFT_NEWER: + toolTip->show(_("Files that exist on both sides, left one is newer"), pos, GlobalResources::getInstance().bitmapLeftNewerAct); + break; + case FILE_RIGHT_NEWER: + toolTip->show(_("Files that exist on both sides, right one is newer"), pos, GlobalResources::getInstance().bitmapRightNewerAct); + break; + case FILE_DIFFERENT: + toolTip->show(_("Files that exist on both sides and have different content"), pos, GlobalResources::getInstance().bitmapDifferentAct); + break; + case FILE_EQUAL: + toolTip->show(_(""), pos, GlobalResources::getInstance().bitmapEqualAct); + break; + case FILE_CONFLICT: + toolTip->show(rowData->conflictDescription.get(), pos, GlobalResources::getInstance().bitmapConflictAct); + break; + } + } } @@ -1594,32 +1693,6 @@ 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); } @@ -1643,6 +1716,8 @@ void GridCellRendererMiddle::Draw(wxGrid& grid, { if (rect.GetWidth() > CHECK_BOX_WIDTH) { + const bool rowIsHighlighted = row == m_gridMiddle->highlightedRow; + wxRect rectShrinked(rect); //clean first block of rect that will receive image of checkbox @@ -1651,14 +1726,17 @@ void GridCellRendererMiddle::Draw(wxGrid& grid, //print image into first block rectShrinked.SetX(rect.GetX() + 1); - bool selected = rowData->selectedForSynchronization; //HIGHLIGHTNING: - if ( row == m_gridMiddle->highlightedRow && - m_gridMiddle->highlightedPos == CustomGridMiddle::BLOCKPOS_CHECK_BOX) - selected = !selected; - - if (selected) + if (rowIsHighlighted && m_gridMiddle->highlightedPos == CustomGridMiddle::BLOCKPOS_CHECK_BOX) + { + if (rowData->selectedForSynchronization) + dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapCheckBoxTrueFocus, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + else + dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapCheckBoxFalseFocus, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); + } + //default + else if (rowData->selectedForSynchronization) dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapCheckBoxTrue, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); else dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapCheckBoxFalse, rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); @@ -1674,7 +1752,7 @@ void GridCellRendererMiddle::Draw(wxGrid& grid, //print sync direction into second block //HIGHLIGHTNING: - if (row == m_gridMiddle->highlightedRow && m_gridMiddle->highlightedPos != CustomGridMiddle::BLOCKPOS_CHECK_BOX) + if (rowIsHighlighted && m_gridMiddle->highlightedPos != CustomGridMiddle::BLOCKPOS_CHECK_BOX) switch (m_gridMiddle->highlightedPos) { case CustomGridMiddle::BLOCKPOS_CHECK_BOX: @@ -1691,7 +1769,7 @@ void GridCellRendererMiddle::Draw(wxGrid& grid, } else //default { - const wxBitmap& syncOpIcon = getSyncOpImage(rowData->cmpResult, rowData->selectedForSynchronization, rowData->direction); + const wxBitmap& syncOpIcon = getSyncOpImage(rowData->cmpResult, rowData->selectedForSynchronization, rowData->syncDir); dc.DrawLabel(wxEmptyString, syncOpIcon, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL); } } @@ -1755,3 +1833,30 @@ void CustomGridMiddle::DrawColLabel(wxDC& dc, int col) dc.DrawLabel(wxEmptyString, *GlobalResources::getInstance().bitmapCmpViewSmall, rect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL); } + +const wxBitmap& FreeFileSync::getSyncOpImage(const CompareFilesResult cmpResult, + const bool selectedForSynchronization, + const SyncDirection syncDir) +{ + switch (getSyncOperation(cmpResult, selectedForSynchronization, syncDir)) //evaluate comparison result and sync direction + { + case SO_CREATE_NEW_LEFT: + return *GlobalResources::getInstance().bitmapCreateLeftSmall; + case SO_CREATE_NEW_RIGHT: + return *GlobalResources::getInstance().bitmapCreateRightSmall; + case SO_DELETE_LEFT: + return *GlobalResources::getInstance().bitmapDeleteLeftSmall; + case SO_DELETE_RIGHT: + return *GlobalResources::getInstance().bitmapDeleteRightSmall; + case SO_OVERWRITE_RIGHT: + return *GlobalResources::getInstance().bitmapSyncDirRightSmall; + case SO_OVERWRITE_LEFT: + return *GlobalResources::getInstance().bitmapSyncDirLeftSmall; + case SO_DO_NOTHING: + return *GlobalResources::getInstance().bitmapSyncDirNoneSmall; + case SO_UNRESOLVED_CONFLICT: + return *GlobalResources::getInstance().bitmapConflictSmall; + } + + return wxNullBitmap; //dummy +} diff --git a/library/CustomGrid.h b/library/CustomGrid.h index 98e86e11..a71b985a 100644 --- a/library/CustomGrid.h +++ b/library/CustomGrid.h @@ -3,7 +3,6 @@ #include <vector> #include <wx/grid.h> -#include "../structures.h" #include "processXml.h" #include <map> #include <memory> @@ -14,6 +13,7 @@ class CustomGridTableRight; class CustomGridTableMiddle; class GridCellRendererMiddle; class wxTimer; +class CustomTooltip; class CustomGridRim; class CustomGridLeft; class CustomGridMiddle; @@ -22,6 +22,10 @@ class CustomGridRight; namespace FreeFileSync { class GridView; + + const wxBitmap& getSyncOpImage(const CompareFilesResult cmpResult, + const bool selectedForSynchronization, + const SyncDirection syncDir); } //################################################################################## @@ -103,7 +107,7 @@ class GridCellRenderer; //----------------------------------------------------------- #ifdef FFS_WIN -class IconUpdater : public wxEvtHandler //update file icons periodically: use SINGLE instance to coordinate left and right grid at once +class IconUpdater : private wxEvtHandler //update file icons periodically: use SINGLE instance to coordinate left and right grid at once { public: IconUpdater(CustomGridLeft* leftGrid, CustomGridRight* rightGrid); @@ -123,8 +127,8 @@ private: class CustomGridRim : public CustomGrid { friend class IconUpdater; - template <bool showFileIcons> - friend class GridCellRenderer; + template <bool showFileIcons> + friend class GridCellRenderer; public: CustomGridRim(wxWindow *parent, @@ -257,6 +261,8 @@ private: void OnLeftMouseDown(wxMouseEvent& event); void OnLeftMouseUp(wxMouseEvent& event); + void showToolTip(int rowNumber, wxPoint pos); + //small helper methods enum BlockPosition //each cell can be divided into four blocks concerning mouse selections { @@ -276,6 +282,8 @@ private: BlockPosition highlightedPos; CustomGridTableMiddle* gridDataTable; + + std::auto_ptr<CustomTooltip> toolTip; }; //custom events for middle grid: diff --git a/library/errorLogging.cpp b/library/errorLogging.cpp new file mode 100644 index 00000000..000dce4d --- /dev/null +++ b/library/errorLogging.cpp @@ -0,0 +1,48 @@ +#include "errorLogging.h" +#include <wx/datetime.h> +#include <wx/intl.h> + + +using FreeFileSync::ErrorLogging; + + +void ErrorLogging::logError(const wxString& errorMessage) +{ + ++errorCount; + + const wxString prefix = wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ") + _("Error") + wxT(": "); + formattedMessages.push_back(assembleMessage(prefix, errorMessage)); +} + + +void ErrorLogging::logWarning(const wxString& warningMessage) +{ + const wxString prefix = wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ") + _("Warning") + wxT(": "); + formattedMessages.push_back(assembleMessage(prefix, warningMessage)); +} + + +void ErrorLogging::logInfo(const wxString& infoMessage) +{ + const wxString prefix = wxString(wxT("[")) + wxDateTime::Now().FormatTime() + wxT("] ") + _("Info") + wxT(": "); + formattedMessages.push_back(assembleMessage(prefix, infoMessage)); +} + + +wxString ErrorLogging::assembleMessage(const wxString& prefix, const wxString& message) +{ + const size_t prefixLength = prefix.size(); + wxString formattedText = prefix; + for (wxString::const_iterator i = message.begin(); i != message.end(); ++i) + if (*i == wxChar('\n')) + { + formattedText += wxString(wxChar('\n')).Pad(prefixLength, wxChar(' '), true); + while (*++i == wxChar('\n')) //remove duplicate newlines + ; + --i; + } + else + formattedText += *i; + + return formattedText; +} diff --git a/library/errorLogging.h b/library/errorLogging.h new file mode 100644 index 00000000..5fc5dacd --- /dev/null +++ b/library/errorLogging.h @@ -0,0 +1,43 @@ +#ifndef ERRORLOGGING_H_INCLUDED +#define ERRORLOGGING_H_INCLUDED + +#include <wx/string.h> +#include <vector> + +class Zstring; + +namespace FreeFileSync +{ + class ErrorLogging + { + public: + ErrorLogging() : errorCount(0) {} + + void logError(const wxString& errorMessage); + void logWarning(const wxString& warningMessage); + void logInfo(const wxString& infoMessage); + + int errorsTotal() + { + return errorCount; + } + + const std::vector<wxString>& getFormattedMessages() + { + return formattedMessages; + } + + size_t messageCount() + { + return formattedMessages.size(); + } + + private: + wxString assembleMessage(const wxString& prefix, const wxString& message); + + std::vector<wxString> formattedMessages; //list of non-resolved errors and warnings + int errorCount; + }; +} + +#endif // ERRORLOGGING_H_INCLUDED diff --git a/library/filter.cpp b/library/filter.cpp index 65513630..bd281c7c 100644 --- a/library/filter.cpp +++ b/library/filter.cpp @@ -1,10 +1,10 @@ #include "filter.h" -#include "zstring.h" +#include "../shared/zstring.h" #include <wx/string.h> #include <set> #include <vector> -#include "resources.h" -#include "globalFunctions.h" +#include "../shared/globalFunctions.h" +#include "../structures.h" using FreeFileSync::FilterProcess; @@ -49,7 +49,7 @@ std::vector<Zstring> compoundStringToFilter(const Zstring& filterString) std::vector<Zstring> newEntries; compoundStringToTable(*i, wxT("\n"), newEntries); - globalFunctions::mergeVectors(newEntries, filterList); + filterList.insert(filterList.end(), newEntries.begin(), newEntries.end()); } return filterList; @@ -70,12 +70,12 @@ void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, st #endif //remove leading separators (keep BEFORE test for Zstring::empty()!) - if (filterFormatted.length() > 0 && *filterFormatted.c_str() == FreeFileSync::FILE_NAME_SEPARATOR) + if (filterFormatted.length() > 0 && *filterFormatted.c_str() == globalFunctions::FILE_NAME_SEPARATOR) filterFormatted = Zstring(filterFormatted.c_str() + 1); if (!filterFormatted.empty()) { - //Test if filterFormatted ends with FreeFileSync::FILE_NAME_SEPARATOR, ignoring '*' and '?'. + //Test if filterFormatted ends with globalFunctions::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; @@ -87,7 +87,7 @@ void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, st break; } - if (i >= 0 && filter[i] == FreeFileSync::FILE_NAME_SEPARATOR) //last FILE_NAME_SEPARATOR found + if (i >= 0 && filter[i] == globalFunctions::FILE_NAME_SEPARATOR) //last FILE_NAME_SEPARATOR found { if (i != int(filterFormatted.length()) - 1) // "name\*" { @@ -119,7 +119,7 @@ bool matchesFilter(const DefaultChar* name, const std::set<Zstring>& filter) #endif for (std::set<Zstring>::const_iterator j = filter.begin(); j != filter.end(); ++j) - if (Zstring::Matches(nameFormatted, *j)) + if (Zstring::Matches(nameFormatted, j->c_str())) return true; return false; diff --git a/library/filter.h b/library/filter.h index 85df591c..53e4d9b1 100644 --- a/library/filter.h +++ b/library/filter.h @@ -1,6 +1,9 @@ #ifndef FFS_FILTER_H_INCLUDED #define FFS_FILTER_H_INCLUDED +#include <wx/string.h> +#include "../shared/zstring.h" +#include <set> #include "../structures.h" diff --git a/library/iconBuffer.cpp b/library/iconBuffer.cpp index a969f689..f73164e0 100644 --- a/library/iconBuffer.cpp +++ b/library/iconBuffer.cpp @@ -1,11 +1,9 @@ #include "iconBuffer.h" #include <wx/thread.h> -#include "globalFunctions.h" -#include <wx/utils.h> +#include "../shared/globalFunctions.h" #include <wx/bitmap.h> #include <wx/msw/wrapwin.h> //includes "windows.h" #include <wx/msgdlg.h> -#include "../algorithm.h" #include <wx/icon.h> #include <map> #include <queue> @@ -13,53 +11,7 @@ using FreeFileSync::IconBuffer; -class BasicString //simple thread safe string class -{ -public: - BasicString() - { - data = new DefaultChar[1]; //compliance with delete [] - *data = 0; //compliance with c_str() - } - - BasicString(const Zstring& other) //make DEEP COPY from Zstring! - { - data = new DefaultChar[other.length() + 1]; - memcpy(data, other.c_str(), (other.length() + 1) * sizeof(DefaultChar)); - } - - BasicString(const BasicString& other) - { - const size_t otherLen = defaultLength(other.c_str()); - data = new DefaultChar[otherLen + 1]; - memcpy(data, other.c_str(), (otherLen + 1) * sizeof(DefaultChar)); - } - - ~BasicString() - { - delete [] data; - } - - BasicString& operator=(const BasicString& other) - { //exception safety; handle self-assignment implicitly - const size_t otherLen = defaultLength(other.c_str()); - DefaultChar* dataNew = new DefaultChar[otherLen + 1]; - memcpy(dataNew, other.c_str(), (otherLen + 1) * sizeof(DefaultChar)); - - delete data; - data = dataNew; - - return *this; - } - - const DefaultChar* c_str() const - { - return data; - } - -private: - DefaultChar* data; -}; +typedef std::vector<DefaultChar> BasicString; //simple thread safe string class: std::vector is guaranteed to not use reference counting, Effective STL, item 13 class WorkerThread : public wxThread @@ -123,7 +75,7 @@ void WorkerThread::setWorkload(const std::vector<Zstring>& load) //(re-)set new workload.clear(); for (std::vector<Zstring>::const_iterator i = load.begin(); i != load.end(); ++i) - workload.push_back(*i); //make DEEP COPY from Zstring! + workload.push_back(FileName(i->c_str(), i->c_str() + i->length() + 1)); //make DEEP COPY from Zstring (include null-termination)! if (!workload.empty()) continueWork.Signal(); //wake thread IF he is waiting @@ -132,9 +84,12 @@ void WorkerThread::setWorkload(const std::vector<Zstring>& load) //(re-)set new void WorkerThread::quitThread() { - wxMutexLocker dummy(threadIsListening); //wait until thread is in waiting state - threadExitIsRequested = true; //no sharing conflicts in this situation - continueWork.Signal(); //exit thread + { + wxMutexLocker dummy(threadIsListening); //wait until thread is in waiting state + threadExitIsRequested = true; //no sharing conflicts in this situation + continueWork.Signal(); //exit thread + } + Wait(); //wait until thread has exitted } @@ -144,7 +99,7 @@ wxThread::ExitCode WorkerThread::Entry() { wxMutexLocker dummy(threadIsListening); //this lock needs to be called from WITHIN the thread => calling it from constructor(Main thread) would be useless { //this mutex STAYS locked all the time except of continueWork.Wait()! - wxCriticalSectionLocker dummy(lockWorkload); + wxCriticalSectionLocker dummy2(lockWorkload); threadHasMutex = true; } @@ -170,7 +125,7 @@ wxThread::ExitCode WorkerThread::Entry() void WorkerThread::doWork() { - BasicString fileName; //don't use Zstring: reference-counted objects are NOT THREADSAFE!!! e.g. double deletion might happen + FileName fileName; //don't use Zstring: reference-counted objects are NOT THREADSAFE!!! e.g. double deletion might happen //do work: get the file icon. while (true) @@ -183,38 +138,46 @@ void WorkerThread::doWork() workload.pop_back(); } - if (iconBuffer->requestIcon(Zstring(fileName.c_str()))) //thread safety: Zstring okay, won't be reference-counted in requestIcon() + if (iconBuffer->requestIcon(Zstring(&fileName[0]))) //thread safety: Zstring okay, won't be reference-counted in requestIcon(), fileName is NOT empty break; //icon already in buffer: enter waiting state - //load icon - SHFILEINFO fileInfo; - fileInfo.hIcon = 0; //initialize hIcon - - if (SHGetFileInfo(fileName.c_str(), //NOTE: CoInitializeEx()/CoUninitialize() implicitly called by wxWidgets on program startup! - 0, - &fileInfo, - sizeof(fileInfo), - SHGFI_ICON | SHGFI_SMALLICON) && - - fileInfo.hIcon != 0) //fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!! - { //bug report: https://sourceforge.net/tracker/?func=detail&aid=2768004&group_id=234430&atid=1093080 - - wxIcon newIcon; //attention: wxIcon uses reference counting! - newIcon.SetHICON(fileInfo.hIcon); - newIcon.SetSize(IconBuffer::ICON_SIZE, IconBuffer::ICON_SIZE); - - iconBuffer->insertIntoBuffer(fileName.c_str(), newIcon); //thread safety: icon may be deleted only within insertIntoBuffer() - - //freeing of icon handle seems to happen somewhere beyond wxIcon destructor - //if (!DestroyIcon(fileInfo.hIcon)) - // throw RuntimeException(wxString(wxT("Error deallocating Icon handle!\n\n")) + FreeFileSync::getLastErrorFormatted()); - - } - else + //despite what docu says about SHGetFileInfo() it can't handle all relative filenames, e.g. "\DirName" + const unsigned int BUFFER_SIZE = 10000; + DefaultChar fullName[BUFFER_SIZE]; + const DWORD rv = ::GetFullPathName( + &fileName[0], //__in LPCTSTR lpFileName, + BUFFER_SIZE, //__in DWORD nBufferLength, + fullName, //__out LPTSTR lpBuffer, + NULL); //__out LPTSTR *lpFilePart + if (rv < BUFFER_SIZE && rv != 0) { - //if loading of icon fails for whatever reason, just save a dummy icon to avoid re-loading - iconBuffer->insertIntoBuffer(fileName.c_str(), wxNullIcon); + //load icon + SHFILEINFO fileInfo; + fileInfo.hIcon = 0; //initialize hIcon + + if (::SHGetFileInfo(fullName, //NOTE: CoInitializeEx()/CoUninitialize() implicitly called by wxWidgets on program startup! + 0, + &fileInfo, + sizeof(fileInfo), + SHGFI_ICON | SHGFI_SMALLICON) && + + fileInfo.hIcon != 0) //fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!! + { //bug report: https://sourceforge.net/tracker/?func=detail&aid=2768004&group_id=234430&atid=1093080 + + wxIcon newIcon; //attention: wxIcon uses reference counting! + newIcon.SetHICON(fileInfo.hIcon); + newIcon.SetSize(IconBuffer::ICON_SIZE, IconBuffer::ICON_SIZE); + + iconBuffer->insertIntoBuffer(&fileName[0], newIcon); //thread safety: icon may be deleted only within insertIntoBuffer() + + //freeing of icon handle seems to happen somewhere beyond wxIcon destructor + //if (!DestroyIcon(fileInfo.hIcon)) + // throw RuntimeException(wxString(wxT("Error deallocating Icon handle!\n\n")) + FreeFileSync::getLastErrorFormatted()); + continue; + } } + //if loading of icon fails for whatever reason, just save a dummy icon to avoid re-loading + iconBuffer->insertIntoBuffer(&fileName[0], wxNullIcon); } } @@ -245,7 +208,6 @@ IconBuffer::IconBuffer() : IconBuffer::~IconBuffer() { worker->quitThread(); - worker->Wait(); //wait until thread has exitted } diff --git a/library/iconBuffer.h b/library/iconBuffer.h index ba905d22..f62a2772 100644 --- a/library/iconBuffer.h +++ b/library/iconBuffer.h @@ -2,11 +2,11 @@ #define ICONBUFFER_H_INCLUDED #ifndef FFS_WIN -#warning //this header should be used in the windows build only! +header should be used in the windows build only! #endif #include <vector> -#include "zstring.h" +#include "../shared/zstring.h" #include <memory> class wxCriticalSection; diff --git a/library/pch.h b/library/pch.h index b561d448..22ed251f 100644 --- a/library/pch.h +++ b/library/pch.h @@ -25,6 +25,7 @@ do NOT use in release build! #include <stack> #include <set> #include <map> +#include <memory> #include <fstream> #ifdef FFS_LINUX @@ -85,7 +86,7 @@ do NOT use in release build! #include <wx/notebook.h> //other -#include "tinyxml/tinyxml.h" +#include "../shared/tinyxml/tinyxml.h" #include <sys/stat.h> #ifdef FFS_WIN diff --git a/library/processXml.cpp b/library/processXml.cpp index 4b8ffe27..43d7fdb9 100644 --- a/library/processXml.cpp +++ b/library/processXml.cpp @@ -1,9 +1,10 @@ #include "processXml.h" +#include "../shared/xmlBase.h" #include <wx/filefn.h> -#include <wx/ffile.h> #include <wx/intl.h> -#include "globalFunctions.h" -#include "tinyxml/tinyxml.h" +#include "../shared/globalFunctions.h" +#include "../shared/fileHandling.h" +#include "../shared/standardPaths.h" #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" @@ -12,290 +13,142 @@ using namespace FreeFileSync; -//small helper functions -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(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 SyncDirection value); -void addXmlElement(TiXmlElement* parent, const std::string& name, const bool value); - - -class XmlConfigInput +class FfsXmlParser : public xmlAccess::XmlParser { public: - XmlConfigInput(const wxString& fileName, const xmlAccess::XmlType type); - ~XmlConfigInput() {} - - bool loadedSuccessfully() - { - return loadSuccess; - } + FfsXmlParser(const TiXmlElement* rootElement) : xmlAccess::XmlParser(rootElement) {} //read gui settings, all values retrieved are optional, so check for initial values! (== -1) - bool readXmlGuiConfig(xmlAccess::XmlGuiConfig& outputCfg); + void readXmlGuiConfig(xmlAccess::XmlGuiConfig& outputCfg); //read batch settings, all values retrieved are optional - bool readXmlBatchConfig(xmlAccess::XmlBatchConfig& outputCfg); + void readXmlBatchConfig(xmlAccess::XmlBatchConfig& outputCfg); //read global settings, valid for both GUI and batch mode, independent from configuration - bool readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputCfg); + void readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputCfg); private: //read basic FreefileSync settings (used by commandline and GUI), return true if ALL values have been retrieved successfully - bool readXmlMainConfig(MainConfiguration& mainCfg, std::vector<FolderPair>& directoryPairs); - - TiXmlDocument doc; - bool loadSuccess; + void readXmlMainConfig(MainConfiguration& mainCfg, std::vector<FolderPair>& directoryPairs); }; -class XmlConfigOutput -{ -public: - XmlConfigOutput(const wxString& fileName, const xmlAccess::XmlType type); - ~XmlConfigOutput() {} - - bool writeToFile(); - - //write gui settings - bool writeXmlGuiConfig(const xmlAccess::XmlGuiConfig& outputCfg); - //write batch settings - bool writeXmlBatchConfig(const xmlAccess::XmlBatchConfig& outputCfg); - //write global settings - bool writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& outputCfg); - -private: - //write basic FreefileSync settings (used by commandline and GUI), return true if everything was written successfully - bool writeXmlMainConfig(const MainConfiguration& mainCfg, const std::vector<FolderPair>& directoryPairs); - - TiXmlDocument doc; - const wxString& m_fileName; -}; - - -xmlAccess::XmlType xmlAccess::getXmlType(const wxString& filename) -{ - if (!wxFileExists(filename)) - return XML_OTHER; - - //workaround to get a FILE* from a unicode filename - wxFFile configFile(filename, wxT("rb")); - if (!configFile.IsOpened()) - return XML_OTHER; - - FILE* inputFile = configFile.fp(); - - TiXmlDocument doc; - if (!doc.LoadFile(inputFile)) //fails if inputFile is no proper XML - return XML_OTHER; - - TiXmlElement* root = doc.RootElement(); - - if (!root || (root->ValueStr() != std::string("FreeFileSync"))) //check for FFS configuration xml - return XML_OTHER; +//write gui settings +bool writeXmlGuiConfig(const xmlAccess::XmlGuiConfig& outputCfg, TiXmlDocument& doc); +//write batch settings +bool writeXmlBatchConfig(const xmlAccess::XmlBatchConfig& outputCfg, TiXmlDocument& doc); +//write global settings +bool writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& outputCfg, TiXmlDocument& doc); +//write basic FreefileSync settings (used by commandline and GUI), return true if everything was written successfully +bool writeXmlMainConfig(const MainConfiguration& mainCfg, const std::vector<FolderPair>& directoryPairs, TiXmlDocument& doc); - const char* cfgType = root->Attribute("XmlType"); - if (!cfgType) - return XML_OTHER; - - if (std::string(cfgType) == "BATCH") - return XML_BATCH_CONFIG; - else if (std::string(cfgType) == "GUI") - return XML_GUI_CONFIG; - else if (std::string(cfgType) == "GLOBAL") - return XML_GLOBAL_SETTINGS; - else - return XML_OTHER; -} - -xmlAccess::XmlGuiConfig xmlAccess::readGuiConfig(const wxString& filename) +void xmlAccess::readGuiConfig(const wxString& filename, xmlAccess::XmlGuiConfig& config) { //load XML if (!wxFileExists(filename)) - throw FileError(Zstring(_("File does not exist:")) + wxT(" \"") + filename.c_str() + wxT("\"")); - - XmlConfigInput inputFile(filename, XML_GUI_CONFIG); - - XmlGuiConfig outputCfg; + throw XmlError(wxString(_("File does not exist:")) + wxT(" \"") + filename + wxT("\"")); - if (!inputFile.loadedSuccessfully()) - throw FileError(Zstring(_("Error reading file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); + TiXmlDocument doc; + if (!loadXmlDocument(filename, XML_GUI_CONFIG, doc)) + throw XmlError(wxString(_("Error reading file:")) + wxT(" \"") + filename + wxT("\"")); - if (!inputFile.readXmlGuiConfig(outputCfg)) //read GUI layout configuration - throw FileError(Zstring(_("Error parsing configuration file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); + FfsXmlParser parser(doc.RootElement()); + parser.readXmlGuiConfig(config); //read GUI layout configuration - return outputCfg; + if (parser.errorsOccured()) + throw XmlError(wxString(_("Error parsing configuration file:")) + wxT(" \"") + filename + wxT("\"\n\n") + + parser.getErrorMessageFormatted(), XmlError::WARNING); } -xmlAccess::XmlBatchConfig xmlAccess::readBatchConfig(const wxString& filename) +void xmlAccess::readBatchConfig(const wxString& filename, xmlAccess::XmlBatchConfig& config) { //load XML if (!wxFileExists(filename)) - throw FileError(Zstring(_("File does not exist:")) + wxT(" \"") + filename.c_str() + wxT("\"")); - - XmlConfigInput inputFile(filename, XML_BATCH_CONFIG); - - XmlBatchConfig outputCfg; + throw XmlError(wxString(_("File does not exist:")) + wxT(" \"") + filename + wxT("\"")); - if (!inputFile.loadedSuccessfully()) - throw FileError(Zstring(_("Error reading file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); + TiXmlDocument doc; + if (!loadXmlDocument(filename, XML_BATCH_CONFIG, doc)) + throw XmlError(wxString(_("Error reading file:")) + wxT(" \"") + filename + wxT("\"")); - if (!inputFile.readXmlBatchConfig(outputCfg)) - throw FileError(Zstring(_("Error parsing configuration file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); + FfsXmlParser parser(doc.RootElement()); + parser.readXmlBatchConfig(config); //read GUI layout configuration - return outputCfg; + if (parser.errorsOccured()) + throw XmlError(wxString(_("Error parsing configuration file:")) + wxT(" \"") + filename + wxT("\"\n\n") + + parser.getErrorMessageFormatted(), XmlError::WARNING); } -xmlAccess::XmlGlobalSettings xmlAccess::readGlobalSettings() +void xmlAccess::readGlobalSettings(xmlAccess::XmlGlobalSettings& config) { //load XML if (!wxFileExists(FreeFileSync::getGlobalConfigFile())) - throw FileError(Zstring(_("File does not exist:")) + wxT(" \"") + FreeFileSync::getGlobalConfigFile().c_str() + wxT("\"")); - - XmlConfigInput inputFile(FreeFileSync::getGlobalConfigFile(), XML_GLOBAL_SETTINGS); - - XmlGlobalSettings outputCfg; + throw XmlError(wxString(_("File does not exist:")) + wxT(" \"") + FreeFileSync::getGlobalConfigFile() + wxT("\"")); - if (!inputFile.loadedSuccessfully()) - throw FileError(Zstring(_("Error reading file:")) + wxT(" \"") + FreeFileSync::getGlobalConfigFile().c_str() + wxT("\"")); + TiXmlDocument doc; + if (!loadXmlDocument(FreeFileSync::getGlobalConfigFile(), XML_GLOBAL_SETTINGS, doc)) + throw XmlError(wxString(_("Error reading file:")) + wxT(" \"") + FreeFileSync::getGlobalConfigFile() + wxT("\"")); - if (!inputFile.readXmlGlobalSettings(outputCfg)) - throw FileError(Zstring(_("Error parsing configuration file:")) + wxT(" \"") + FreeFileSync::getGlobalConfigFile().c_str() + wxT("\"")); + FfsXmlParser parser(doc.RootElement()); + parser.readXmlGlobalSettings(config); //read GUI layout configuration - return outputCfg; + if (parser.errorsOccured()) + throw XmlError(wxString(_("Error parsing configuration file:")) + wxT(" \"") + FreeFileSync::getGlobalConfigFile() + wxT("\"\n\n") + + parser.getErrorMessageFormatted(), XmlError::WARNING); } -void xmlAccess::writeGuiConfig(const wxString& filename, const XmlGuiConfig& outputCfg) +void xmlAccess::writeGuiConfig(const XmlGuiConfig& outputCfg, const wxString& filename) { - XmlConfigOutput outputFile(filename, XML_GUI_CONFIG); + TiXmlDocument doc; + getDefaultXmlDocument(XML_GUI_CONFIG, doc); //populate and write XML tree - if ( !outputFile.writeXmlGuiConfig(outputCfg) || //add GUI layout configuration settings - !outputFile.writeToFile()) //save XML - throw FileError(Zstring(_("Error writing file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); + if ( !writeXmlGuiConfig(outputCfg, doc) || //add GUI layout configuration settings + !saveXmlDocument(filename, doc)) //save XML + throw XmlError(wxString(_("Error writing file:")) + wxT(" \"") + filename + wxT("\"")); return; } -void xmlAccess::writeBatchConfig(const wxString& filename, const XmlBatchConfig& outputCfg) +void xmlAccess::writeBatchConfig(const XmlBatchConfig& outputCfg, const wxString& filename) { - XmlConfigOutput outputFile(filename, XML_BATCH_CONFIG); + TiXmlDocument doc; + getDefaultXmlDocument(XML_BATCH_CONFIG, doc); //populate and write XML tree - if ( !outputFile.writeXmlBatchConfig(outputCfg) || //add batch configuration settings - !outputFile.writeToFile()) //save XML - throw FileError(Zstring(_("Error writing file:")) + wxT(" \"") + filename.c_str() + wxT("\"")); + if ( !writeXmlBatchConfig(outputCfg, doc) || //add batch configuration settings + !saveXmlDocument(filename, doc)) //save XML + throw XmlError(wxString(_("Error writing file:")) + wxT(" \"") + filename + wxT("\"")); return; } void xmlAccess::writeGlobalSettings(const XmlGlobalSettings& outputCfg) { - XmlConfigOutput outputFile(FreeFileSync::getGlobalConfigFile(), XML_GLOBAL_SETTINGS); + TiXmlDocument doc; + getDefaultXmlDocument(XML_GLOBAL_SETTINGS, doc); //populate and write XML tree - if ( !outputFile.writeXmlGlobalSettings(outputCfg) || //add GUI layout configuration settings - !outputFile.writeToFile()) //save XML - throw FileError(Zstring(_("Error writing file:")) + wxT(" \"") + FreeFileSync::getGlobalConfigFile().c_str() + wxT("\"")); + if ( !writeXmlGlobalSettings(outputCfg, doc) || //add GUI layout configuration settings + !saveXmlDocument(FreeFileSync::getGlobalConfigFile(), doc)) //save XML + throw XmlError(wxString(_("Error writing file:")) + wxT(" \"") + FreeFileSync::getGlobalConfigFile() + wxT("\"")); return; } -XmlConfigInput::XmlConfigInput(const wxString& fileName, const xmlAccess::XmlType type) : - loadSuccess(false) -{ - if (!wxFileExists(fileName)) //avoid wxWidgets error message when wxFFile receives not existing file - return; - - //workaround to get a FILE* from a unicode filename - wxFFile dummyFile(fileName, wxT("rb")); - if (dummyFile.IsOpened()) - { - FILE* inputFile = dummyFile.fp(); - - TiXmlBase::SetCondenseWhiteSpace(false); //do not condense whitespace characters - - if (doc.LoadFile(inputFile)) //load XML; fails if inputFile is no proper XML - { - TiXmlElement* root = doc.RootElement(); - - if (root && (root->ValueStr() == std::string("FreeFileSync"))) //check for FFS configuration xml - { - const char* cfgType = root->Attribute("XmlType"); - if (cfgType) - { - if (type == xmlAccess::XML_GUI_CONFIG) - loadSuccess = std::string(cfgType) == "GUI"; - else if (type == xmlAccess::XML_BATCH_CONFIG) - loadSuccess = std::string(cfgType) == "BATCH"; - else if (type == xmlAccess::XML_GLOBAL_SETTINGS) - loadSuccess = std::string(cfgType) == "GLOBAL"; - } - } - } - } -} - - -bool readXmlElementValue(std::string& output, const TiXmlElement* parent, const std::string& name) +bool readXmlElement(const std::string& name, const TiXmlElement* parent, CompareVariant& output) { - if (parent) - { - const TiXmlElement* child = parent->FirstChildElement(name); - if (child) - { - const char* text = child->GetText(); - if (text) //may be NULL!! - output = text; - else - output.clear(); - return true; - } - } - - return false; -} - - -bool readXmlElementValue(int& output, const TiXmlElement* parent, const std::string& name) -{ - std::string temp; - if (readXmlElementValue(temp, parent, name)) - { - output = globalFunctions::stringToInt(temp); - return true; - } - else - return false; -} - - -bool readXmlElementValue(long& output, const TiXmlElement* parent, const std::string& name) -{ - std::string temp; - if (readXmlElementValue(temp, parent, name)) + std::string dummy; + if (xmlAccess::readXmlElement(name, parent, dummy)) { - output = globalFunctions::stringToLong(temp); - return true; - } - else - return false; -} + if (dummy == "ByTimeAndSize") + output = FreeFileSync::CMP_BY_TIME_SIZE; + else if (dummy == "ByContent") + output = FreeFileSync::CMP_BY_CONTENT; + else + return false; - -bool readXmlElementValue(CompareVariant& output, const TiXmlElement* parent, const std::string& name) -{ - int dummy = 0; - if (readXmlElementValue(dummy, parent, name)) - { - output = CompareVariant(dummy); return true; } else @@ -303,17 +156,17 @@ bool readXmlElementValue(CompareVariant& output, const TiXmlElement* parent, con } -bool readXmlElementValue(SyncDirection& output, const TiXmlElement* parent, const std::string& name) +bool readXmlElement(const std::string& name, const TiXmlElement* parent, SyncDirectionCfg& output) { std::string dummy; - if (readXmlElementValue(dummy, parent, name)) + if (xmlAccess::readXmlElement(name, parent, dummy)) { if (dummy == "left") - output = SYNC_DIR_LEFT; + output = SYNC_DIR_CFG_LEFT; else if (dummy == "right") - output = SYNC_DIR_RIGHT; + output = SYNC_DIR_CFG_RIGHT; else //treat all other input as "none" - output = SYNC_DIR_NONE; + output = SYNC_DIR_CFG_NONE; return true; } @@ -322,23 +175,10 @@ bool readXmlElementValue(SyncDirection& output, const TiXmlElement* parent, cons } -bool readXmlElementValue(bool& output, const TiXmlElement* parent, const std::string& name) -{ - std::string dummy; - if (readXmlElementValue(dummy, parent, name)) - { - output = (dummy == "true"); - return true; - } - else - return false; -} - - -bool readXmlElementValue(xmlAccess::OnError& output, const TiXmlElement* parent, const std::string& name) +bool readXmlElement(const std::string& name, const TiXmlElement* parent, xmlAccess::OnError& output) { std::string dummy; - if (readXmlElementValue(dummy, parent, name)) + if (xmlAccess::readXmlElement(name, parent, dummy)) { if (dummy == "Ignore") output = xmlAccess::ON_ERROR_IGNORE; @@ -354,430 +194,319 @@ bool readXmlElementValue(xmlAccess::OnError& output, const TiXmlElement* parent, } -void readXmlElementTable(std::vector<wxString>& output, const TiXmlElement* parent, const std::string& name) +bool readXmlElement(const std::string& name, const TiXmlElement* parent , FreeFileSync::DeletionPolicy& output) { - output.clear(); - - if (parent) + std::string dummy; + if (xmlAccess::readXmlElement(name, parent, dummy)) { - //load elements - const TiXmlElement* element = parent->FirstChildElement(name); - while (element) - { - const char* text = element->GetText(); - if (text) //may be NULL!! - output.push_back(wxString::FromUTF8(text)); - else - break; - element = element->NextSiblingElement(); - } + if (dummy == "DeletePermanently") + output = FreeFileSync::DELETE_PERMANENTLY; + else if (dummy == "MoveToRecycleBin") + output = FreeFileSync::MOVE_TO_RECYCLE_BIN; + else if (dummy == "MoveToCustomDirectory") + output = FreeFileSync::MOVE_TO_CUSTOM_DIRECTORY; + else + return false; + + return true; } -} -//################################################################################################################ + return false; +} -bool XmlConfigInput::readXmlMainConfig(MainConfiguration& mainCfg, std::vector<FolderPair>& directoryPairs) +bool readXmlAttribute(const std::string& name, const TiXmlElement* node, xmlAccess::ColumnTypes& output) { - TiXmlElement* root = doc.RootElement(); - if (!root) return false; + int dummy; + if (xmlAccess::readXmlAttribute(name, node, dummy)) + { + output = static_cast<xmlAccess::ColumnTypes>(dummy); + return true; + } + else + return false; +} - TiXmlHandle hRoot(root); - TiXmlElement* cmpSettings = hRoot.FirstChild("MainConfig").FirstChild("Comparison").ToElement(); - TiXmlElement* syncConfig = hRoot.FirstChild("MainConfig").FirstChild("Synchronization").FirstChild("Directions").ToElement(); - TiXmlElement* miscSettings = hRoot.FirstChild("MainConfig").FirstChild("Miscellaneous").ToElement(); - TiXmlElement* filter = TiXmlHandle(miscSettings).FirstChild("Filter").ToElement(); +//################################################################################################################ +void FfsXmlParser::readXmlMainConfig(MainConfiguration& mainCfg, std::vector<FolderPair>& directoryPairs) +{ + TiXmlHandleConst hRoot(root); //custom const handle: TiXml API seems broken in this regard - if (!cmpSettings || !syncConfig || !miscSettings || !filter) - return false; + const TiXmlElement* cmpSettings = hRoot.FirstChild("MainConfig").FirstChild("Comparison").ToElement(); + const TiXmlElement* syncConfig = hRoot.FirstChild("MainConfig").FirstChild("Synchronization").FirstChild("Directions").ToElement(); + const TiXmlElement* miscSettings = hRoot.FirstChild("MainConfig").FirstChild("Miscellaneous").ToElement(); + const TiXmlElement* filter = TiXmlHandleConst(miscSettings).FirstChild("Filter").ToElement(); - std::string tempString; //########################################################### //read compare variant - if (!readXmlElementValue(mainCfg.compareVar, cmpSettings, "Variant")) return false; + readXmlElementLogging("Variant", cmpSettings, mainCfg.compareVar); //read folder pair(s) - TiXmlElement* folderPair = TiXmlHandle(cmpSettings).FirstChild("Folders").FirstChild("Pair").ToElement(); + const TiXmlElement* folderPair = TiXmlHandleConst(cmpSettings).FirstChild("Folders").FirstChild("Pair").ToElement(); //read folder pairs directoryPairs.clear(); while (folderPair) { - FolderPair newPair; - - if (!readXmlElementValue(tempString, folderPair, "Left")) return false; - newPair.leftDirectory = wxString::FromUTF8(tempString.c_str()).c_str(); - - if (!readXmlElementValue(tempString, folderPair, "Right")) return false; - newPair.rightDirectory = wxString::FromUTF8(tempString.c_str()).c_str(); - - directoryPairs.push_back(newPair); + wxString temp; + wxString temp2; + readXmlElementLogging("Left", folderPair, temp); + readXmlElementLogging("Right", folderPair, temp2); + directoryPairs.push_back(FolderPair(temp.c_str(), temp2.c_str())); folderPair = folderPair->NextSiblingElement(); } //########################################################### //read sync configuration - if (!readXmlElementValue(mainCfg.syncConfiguration.exLeftSideOnly, syncConfig, "LeftOnly")) return false; - if (!readXmlElementValue(mainCfg.syncConfiguration.exRightSideOnly, syncConfig, "RightOnly")) return false; - if (!readXmlElementValue(mainCfg.syncConfiguration.leftNewer, syncConfig, "LeftNewer")) return false; - if (!readXmlElementValue(mainCfg.syncConfiguration.rightNewer, syncConfig, "RightNewer")) return false; - if (!readXmlElementValue(mainCfg.syncConfiguration.different, syncConfig, "Different")) return false; + readXmlElementLogging("LeftOnly", syncConfig, mainCfg.syncConfiguration.exLeftSideOnly); + readXmlElementLogging("RightOnly", syncConfig, mainCfg.syncConfiguration.exRightSideOnly); + readXmlElementLogging("LeftNewer", syncConfig, mainCfg.syncConfiguration.leftNewer); + readXmlElementLogging("RightNewer", syncConfig, mainCfg.syncConfiguration.rightNewer); + readXmlElementLogging("Different", syncConfig, mainCfg.syncConfiguration.different); + //########################################################### //read filter settings - if (!readXmlElementValue(mainCfg.filterIsActive, filter, "Active")) return false; - - if (!readXmlElementValue(tempString, filter, "Include")) return false; - mainCfg.includeFilter = wxString::FromUTF8(tempString.c_str()); - - if (!readXmlElementValue(tempString, filter, "Exclude")) return false; - mainCfg.excludeFilter = wxString::FromUTF8(tempString.c_str()); + readXmlElementLogging("Active", filter, mainCfg.filterIsActive); + readXmlElementLogging("Include", filter, mainCfg.includeFilter); + readXmlElementLogging("Exclude", filter, mainCfg.excludeFilter); //########################################################### //other - readXmlElementValue(mainCfg.useRecycleBin, miscSettings, "UseRecycler"); - - return true; + readXmlElementLogging("DeletionPolicy", miscSettings, mainCfg.handleDeletion); + readXmlElementLogging("CustomDeletionFolder", miscSettings, mainCfg.customDeletionDirectory); } -bool XmlConfigInput::readXmlGuiConfig(xmlAccess::XmlGuiConfig& outputCfg) +void FfsXmlParser::readXmlGuiConfig(xmlAccess::XmlGuiConfig& outputCfg) { //read main config - if (!readXmlMainConfig(outputCfg.mainCfg, outputCfg.directoryPairs)) - return false; + readXmlMainConfig(outputCfg.mainCfg, outputCfg.directoryPairs); //read GUI specific config data - TiXmlElement* root = doc.RootElement(); - if (!root) return false; + const TiXmlElement* guiConfig = TiXmlHandleConst(root).FirstChild("GuiConfig").ToElement(); - TiXmlHandle hRoot(root); + readXmlElementLogging("HideFiltered", guiConfig, outputCfg.hideFilteredElements); - TiXmlElement* guiConfig = hRoot.FirstChild("GuiConfig").ToElement(); - if (guiConfig) - { - readXmlElementValue(outputCfg.hideFilteredElements, guiConfig, "HideFiltered"); - readXmlElementValue(outputCfg.ignoreErrors, guiConfig, "IgnoreErrors"); - readXmlElementValue(outputCfg.syncPreviewEnabled, guiConfig, "SyncPreviewActive"); - } + xmlAccess::OnError errorHand; + readXmlElementLogging("HandleError", guiConfig, errorHand); + outputCfg.ignoreErrors = errorHand == xmlAccess::ON_ERROR_IGNORE; - return true; + readXmlElementLogging("SyncPreviewActive", guiConfig, outputCfg.syncPreviewEnabled); } -bool XmlConfigInput::readXmlBatchConfig(xmlAccess::XmlBatchConfig& outputCfg) +void FfsXmlParser::readXmlBatchConfig(xmlAccess::XmlBatchConfig& outputCfg) { //read main config - if (!readXmlMainConfig(outputCfg.mainCfg, outputCfg.directoryPairs)) - return false; + readXmlMainConfig(outputCfg.mainCfg, outputCfg.directoryPairs); //read batch specific config - TiXmlElement* root = doc.RootElement(); - if (!root) return false; - - TiXmlHandle hRoot(root); + const TiXmlElement* batchConfig = TiXmlHandleConst(root).FirstChild("BatchConfig").ToElement(); - //read batch settings - TiXmlElement* batchConfig = hRoot.FirstChild("BatchConfig").ToElement(); - if (batchConfig) - { - readXmlElementValue(outputCfg.silent, batchConfig, "Silent"); - - std::string tempString; - if (readXmlElementValue(tempString, batchConfig, "LogfileDirectory")) - outputCfg.logFileDirectory = wxString::FromUTF8(tempString.c_str()); - - readXmlElementValue(outputCfg.handleError, batchConfig, "HandleError"); - } - - return true; + readXmlElementLogging("Silent", batchConfig, outputCfg.silent); + readXmlElementLogging("LogfileDirectory", batchConfig, outputCfg.logFileDirectory); + readXmlElementLogging("HandleError", batchConfig, outputCfg.handleError); } -bool XmlConfigInput::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputCfg) +void FfsXmlParser::readXmlGlobalSettings(xmlAccess::XmlGlobalSettings& outputCfg) { - TiXmlElement* root = doc.RootElement(); - if (!root) return false; - - TiXmlHandle hRoot(root); - //read global settings - TiXmlElement* global = hRoot.FirstChild("Shared").ToElement(); - if (global) - { - //try to read program language setting - readXmlElementValue(outputCfg.programLanguage, global, "Language"); - - //max. allowed file time deviation - int dummy = 0; - if (readXmlElementValue(dummy, global, "FileTimeTolerance")) - outputCfg.fileTimeTolerance = dummy; - - //ignore +/- 1 hour due to DST change - readXmlElementValue(outputCfg.ignoreOneHourDiff, global, "IgnoreOneHourDifference"); + const TiXmlElement* global = TiXmlHandleConst(root).FirstChild("Shared").ToElement(); - //traverse into symbolic links (to folders) - readXmlElementValue(outputCfg.traverseDirectorySymlinks, global, "TraverseDirectorySymlinks"); + //try to read program language setting + readXmlElementLogging("Language", global, outputCfg.programLanguage); - //copy symbolic links to files - readXmlElementValue(outputCfg.copyFileSymlinks, global, "CopyFileSymlinks"); - - //last update check - readXmlElementValue(outputCfg.lastUpdateCheck, global, "LastCheckForUpdates"); - } + //max. allowed file time deviation + readXmlElementLogging("FileTimeTolerance", global, outputCfg.fileTimeTolerance); - TiXmlElement* warnings = hRoot.FirstChild("Shared").FirstChild("Warnings").ToElement(); - if (warnings) - { - //folder dependency check - readXmlElementValue(outputCfg.warnings.warningDependentFolders, warnings, "CheckForDependentFolders"); + //ignore +/- 1 hour due to DST change + readXmlElementLogging("IgnoreOneHourDifference", global, outputCfg.ignoreOneHourDiff); - //significant difference check - readXmlElementValue(outputCfg.warnings.warningSignificantDifference, warnings, "CheckForSignificantDifference"); + //traverse into symbolic links (to folders) + readXmlElementLogging("TraverseDirectorySymlinks", global, outputCfg.traverseDirectorySymlinks); - //check free disk space - readXmlElementValue(outputCfg.warnings.warningNotEnoughDiskSpace, warnings, "CheckForFreeDiskSpace"); + //copy symbolic links to files + readXmlElementLogging("CopyFileSymlinks", global, outputCfg.copyFileSymlinks); - //check for unresolved conflicts - readXmlElementValue(outputCfg.warnings.warningUnresolvedConflicts, warnings, "CheckForUnresolvedConflicts"); + //last update check + readXmlElementLogging("LastCheckForUpdates", global, outputCfg.lastUpdateCheck); - //check for very old dates or dates in the future - readXmlElementValue(outputCfg.warnings.warningInvalidDate, warnings, "CheckForInvalidFileDate"); - //check for changed files with same modification date - readXmlElementValue(outputCfg.warnings.warningSameDateDiffSize, warnings, "SameDateDifferentFileSize"); + const TiXmlElement* warnings = TiXmlHandleConst(root).FirstChild("Shared").FirstChild("Warnings").ToElement(); - //check for files that have a difference in file modification date below 1 hour when DST check is active - readXmlElementValue(outputCfg.warnings.warningDSTChangeWithinHour, warnings, "FileChangeWithinHour"); - } + //folder dependency check + readXmlElementLogging("CheckForDependentFolders", warnings, outputCfg.warnings.warningDependentFolders); + //significant difference check + readXmlElementLogging("CheckForSignificantDifference", warnings, outputCfg.warnings.warningSignificantDifference); + //check free disk space + readXmlElementLogging("CheckForFreeDiskSpace", warnings, outputCfg.warnings.warningNotEnoughDiskSpace); + //check for unresolved conflicts + readXmlElementLogging("CheckForUnresolvedConflicts", warnings, outputCfg.warnings.warningUnresolvedConflicts); //gui specific global settings (optional) - TiXmlElement* mainWindow = hRoot.FirstChild("Gui").FirstChild("Windows").FirstChild("Main").ToElement(); - if (mainWindow) - { - //read application window size and position - readXmlElementValue(outputCfg.gui.widthNotMaximized, mainWindow, "Width"); - readXmlElementValue(outputCfg.gui.heightNotMaximized, mainWindow, "Height"); - readXmlElementValue(outputCfg.gui.posXNotMaximized, mainWindow, "PosX"); - readXmlElementValue(outputCfg.gui.posYNotMaximized, mainWindow, "PosY"); - readXmlElementValue(outputCfg.gui.isMaximized, mainWindow, "Maximized"); - - readXmlElementValue(outputCfg.gui.deleteOnBothSides, mainWindow, "ManualDeletionOnBothSides"); - readXmlElementValue(outputCfg.gui.useRecyclerForManualDeletion, mainWindow, "ManualDeletionUseRecycler"); - readXmlElementValue(outputCfg.gui.showFileIconsLeft, mainWindow, "ShowFileIconsLeft"); - readXmlElementValue(outputCfg.gui.showFileIconsRight, mainWindow, "ShowFileIconsRight"); - readXmlElementValue(outputCfg.gui.popupOnConfigChange, mainWindow, "PopupOnConfigChange"); - readXmlElementValue(outputCfg.gui.showSummaryBeforeSync, mainWindow, "SummaryBeforeSync"); + const TiXmlElement* mainWindow = TiXmlHandleConst(root).FirstChild("Gui").FirstChild("Windows").FirstChild("Main").ToElement(); + + //read application window size and position + readXmlElementLogging("Width", mainWindow, outputCfg.gui.widthNotMaximized); + readXmlElementLogging("Height", mainWindow, outputCfg.gui.heightNotMaximized); + readXmlElementLogging("PosX", mainWindow, outputCfg.gui.posXNotMaximized); + readXmlElementLogging("PosY", mainWindow, outputCfg.gui.posYNotMaximized); + readXmlElementLogging("Maximized", mainWindow, outputCfg.gui.isMaximized); + + readXmlElementLogging("ManualDeletionOnBothSides", mainWindow, outputCfg.gui.deleteOnBothSides); + readXmlElementLogging("ManualDeletionUseRecycler", mainWindow, outputCfg.gui.useRecyclerForManualDeletion); + readXmlElementLogging("ShowFileIconsLeft", mainWindow, outputCfg.gui.showFileIconsLeft); + readXmlElementLogging("ShowFileIconsRight", mainWindow, outputCfg.gui.showFileIconsRight); + readXmlElementLogging("PopupOnConfigChange", mainWindow, outputCfg.gui.popupOnConfigChange); + readXmlElementLogging("SummaryBeforeSync", mainWindow, outputCfg.gui.showSummaryBeforeSync); //########################################################### - //read column attributes - TiXmlElement* leftColumn = TiXmlHandle(mainWindow).FirstChild("LeftColumns").FirstChild("Column").ToElement(); - unsigned int colPos = 0; - while (leftColumn) - { - const char* type = leftColumn->Attribute("Type"); - const char* visible = leftColumn->Attribute("Visible"); - const char* width = leftColumn->Attribute("Width"); - - if (type && visible && width) //may be NULL!! - { - xmlAccess::ColumnAttrib newAttrib; - newAttrib.type = xmlAccess::ColumnTypes(globalFunctions::stringToInt(type)); - newAttrib.visible = std::string(visible) != std::string("false"); - newAttrib.position = colPos; - newAttrib.width = globalFunctions::stringToInt(width); - outputCfg.gui.columnAttribLeft.push_back(newAttrib); - } - else - break; - - leftColumn = leftColumn->NextSiblingElement(); - ++colPos; - } - - TiXmlElement* rightColumn = TiXmlHandle(mainWindow).FirstChild("RightColumns").FirstChild("Column").ToElement(); - colPos = 0; - while (rightColumn) - { - const char* type = rightColumn->Attribute("Type"); - const char* visible = rightColumn->Attribute("Visible"); - const char* width = rightColumn->Attribute("Width"); - - if (type && visible && width) //may be NULL!! - { - xmlAccess::ColumnAttrib newAttrib; - newAttrib.type = xmlAccess::ColumnTypes(globalFunctions::stringToInt(type)); - newAttrib.visible = std::string(visible) != std::string("false"); - newAttrib.position = colPos; - newAttrib.width = globalFunctions::stringToInt(width); - outputCfg.gui.columnAttribRight.push_back(newAttrib); - } - else - break; - - rightColumn = rightColumn->NextSiblingElement(); - ++colPos; - } - - //load folder history elements - const TiXmlElement* historyLeft = TiXmlHandle(mainWindow).FirstChild("FolderHistoryLeft").ToElement(); - if (historyLeft) - { - //load max. history size - const char* histSizeMax = historyLeft->Attribute("MaximumSize"); - if (histSizeMax) //may be NULL! - outputCfg.gui.folderHistLeftMax = globalFunctions::stringToInt(histSizeMax); - - //load config history elements - readXmlElementTable(outputCfg.gui.folderHistoryLeft, historyLeft, "Folder"); - } - - const TiXmlElement* historyRight = TiXmlHandle(mainWindow).FirstChild("FolderHistoryRight").ToElement(); - if (historyRight) - { - //load max. history size - const char* histSizeMax = historyRight->Attribute("MaximumSize"); - if (histSizeMax) //may be NULL! - outputCfg.gui.folderHistRightMax = globalFunctions::stringToInt(histSizeMax); - - //load config history elements - readXmlElementTable(outputCfg.gui.folderHistoryRight, historyRight, "Folder"); - } - - readXmlElementValue(outputCfg.gui.selectedTabBottomLeft, mainWindow, "SelectedTabBottomLeft"); - } + //read column attributes + readXmlAttributeLogging("AutoAdjust", TiXmlHandleConst(mainWindow).FirstChild("LeftColumns").ToElement(), outputCfg.gui.autoAdjustColumnsLeft); - TiXmlElement* gui = hRoot.FirstChild("Gui").ToElement(); - if (gui) + const TiXmlElement* leftColumn = TiXmlHandleConst(mainWindow).FirstChild("LeftColumns").FirstChild("Column").ToElement(); + unsigned int colPos = 0; + while (leftColumn) { - //commandline for file manager integration - std::string tempString; - if (readXmlElementValue(tempString, gui, "FileManager")) - outputCfg.gui.commandLineFileManager = wxString::FromUTF8(tempString.c_str()); + xmlAccess::ColumnAttrib newAttrib; + newAttrib.position = colPos++; + readXmlAttributeLogging("Type", leftColumn, newAttrib.type); + readXmlAttributeLogging("Visible", leftColumn, newAttrib.visible); + readXmlAttributeLogging("Width", leftColumn, newAttrib.width); + outputCfg.gui.columnAttribLeft.push_back(newAttrib); + + leftColumn = leftColumn->NextSiblingElement(); } - //load config file history - TiXmlElement* cfgHistory = hRoot.FirstChild("Gui").FirstChild("ConfigHistory").ToElement(); - if (cfgHistory) - { - //load max. history size - const char* histSizeMax = cfgHistory->Attribute("MaximumSize"); - if (histSizeMax) //may be NULL! - outputCfg.gui.cfgHistoryMax = globalFunctions::stringToInt(histSizeMax); + readXmlAttributeLogging("AutoAdjust", TiXmlHandleConst(mainWindow).FirstChild("RightColumns").ToElement(), outputCfg.gui.autoAdjustColumnsRight); - //load config history elements - readXmlElementTable(outputCfg.gui.cfgFileHistory, cfgHistory, "File"); + const TiXmlElement* rightColumn = TiXmlHandleConst(mainWindow).FirstChild("RightColumns").FirstChild("Column").ToElement(); + colPos = 0; + while (rightColumn) + { + xmlAccess::ColumnAttrib newAttrib; + newAttrib.position = colPos++; + readXmlAttributeLogging("Type", rightColumn, newAttrib.type); + readXmlAttributeLogging("Visible", rightColumn, newAttrib.visible); + readXmlAttributeLogging("Width", rightColumn, newAttrib.width); + outputCfg.gui.columnAttribRight.push_back(newAttrib); + + rightColumn = rightColumn->NextSiblingElement(); } + //load folder history elements + const TiXmlElement* historyLeft = TiXmlHandleConst(mainWindow).FirstChild("FolderHistoryLeft").ToElement(); + //load max. history size + readXmlAttributeLogging("MaximumSize", historyLeft, outputCfg.gui.folderHistLeftMax); + //load config history elements + readXmlElementLogging("Folder", historyLeft, outputCfg.gui.folderHistoryLeft); -//batch specific global settings - TiXmlElement* batch = hRoot.FirstChild("Batch").ToElement(); - if (!batch) return false; - return true; -} + const TiXmlElement* historyRight = TiXmlHandleConst(mainWindow).FirstChild("FolderHistoryRight").ToElement(); + //load max. history size + readXmlAttributeLogging("MaximumSize", historyRight, outputCfg.gui.folderHistRightMax); + //load config history elements + readXmlElementLogging("Folder", historyRight, outputCfg.gui.folderHistoryRight); -XmlConfigOutput::XmlConfigOutput(const wxString& fileName, const xmlAccess::XmlType type) : - m_fileName(fileName) -{ - TiXmlBase::SetCondenseWhiteSpace(false); //do not condense whitespace characters - - TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "UTF-8", ""); //delete won't be necessary later; ownership passed to TiXmlDocument! - doc.LinkEndChild(decl); - - TiXmlElement* root = new TiXmlElement("FreeFileSync"); - if (type == xmlAccess::XML_GUI_CONFIG) - root->SetAttribute("XmlType", "GUI"); //xml configuration type - else if (type == xmlAccess::XML_BATCH_CONFIG) - root->SetAttribute("XmlType", "BATCH"); - else if (type == xmlAccess::XML_GLOBAL_SETTINGS) - root->SetAttribute("XmlType", "GLOBAL"); - else - assert(false); - doc.LinkEndChild(root); -} + readXmlElementLogging("SelectedTabBottomLeft", mainWindow, outputCfg.gui.selectedTabBottomLeft); -bool XmlConfigOutput::writeToFile() -{ - //workaround to get a FILE* from a unicode filename - wxFFile dummyFile(m_fileName, wxT("w")); //no need for "binary" mode here - if (!dummyFile.IsOpened()) - return false; + const TiXmlElement* gui = TiXmlHandleConst(root).FirstChild("Gui").ToElement(); - FILE* outputFile = dummyFile.fp(); + //commandline for file manager integration + readXmlElementLogging("FileManager", gui, outputCfg.gui.commandLineFileManager); - return doc.SaveFile(outputFile); //save XML -} + //load config file history + const TiXmlElement* cfgHistory = TiXmlHandleConst(root).FirstChild("Gui").FirstChild("ConfigHistory").ToElement(); -void addXmlElement(TiXmlElement* parent, const std::string& name, const std::string& value) -{ - if (parent) - { - TiXmlElement* subElement = new TiXmlElement(name); - parent->LinkEndChild(subElement); - subElement->LinkEndChild(new TiXmlText(value)); - } -} + //load max. history size + readXmlAttributeLogging("MaximumSize", cfgHistory, outputCfg.gui.cfgHistoryMax); + //load config history elements + readXmlElementLogging("File", cfgHistory, outputCfg.gui.cfgFileHistory); -void addXmlElement(TiXmlElement* parent, const std::string& name, const int value) -{ - addXmlElement(parent, name, globalFunctions::numberToString(value)); + + //batch specific global settings + //const TiXmlElement* batch = TiXmlHandleConst(root).FirstChild("Batch").ToElement(); } -void addXmlElement(TiXmlElement* parent, const std::string& name, const long value) +void addXmlElement(const std::string& name, const CompareVariant variant, TiXmlElement* parent) { - addXmlElement(parent, name, globalFunctions::numberToString(value)); + switch (variant) + { + case FreeFileSync::CMP_BY_TIME_SIZE: + xmlAccess::addXmlElement(name, std::string("ByTimeAndSize"), parent); + break; + case FreeFileSync::CMP_BY_CONTENT: + xmlAccess::addXmlElement(name, std::string("ByContent"), parent); + break; + } } -void addXmlElement(TiXmlElement* parent, const std::string& name, const SyncDirection value) +void addXmlElement(TiXmlElement* parent, const std::string& name, const SyncDirectionCfg value) { - if (value == SYNC_DIR_LEFT) - addXmlElement(parent, name, std::string("left")); - else if (value == SYNC_DIR_RIGHT) - addXmlElement(parent, name, std::string("right")); - else if (value == SYNC_DIR_NONE) - addXmlElement(parent, name, std::string("none")); - else - assert(false); + switch (value) + { + case SYNC_DIR_CFG_LEFT: + xmlAccess::addXmlElement(name, std::string("left"), parent); + break; + case SYNC_DIR_CFG_RIGHT: + xmlAccess::addXmlElement(name, std::string("right"), parent); + break; + case SYNC_DIR_CFG_NONE: + xmlAccess::addXmlElement(name, std::string("none"), parent); + break; + } } -void addXmlElement(TiXmlElement* parent, const std::string& name, const bool value) +void addXmlElement(const std::string& name, const xmlAccess::OnError value, TiXmlElement* parent) { - if (value) - addXmlElement(parent, name, std::string("true")); - else - addXmlElement(parent, name, std::string("false")); + switch (value) + { + case xmlAccess::ON_ERROR_IGNORE: + xmlAccess::addXmlElement(name, std::string("Ignore"), parent); + break; + case xmlAccess::ON_ERROR_EXIT: + xmlAccess::addXmlElement(name, std::string("Exit"), parent); + break; + case xmlAccess::ON_ERROR_POPUP: + xmlAccess::addXmlElement(name, std::string("Popup"), parent); + break; + } } -void addXmlElement(TiXmlElement* parent, const std::string& name, const xmlAccess::OnError value) +void addXmlElement(const std::string& name, const FreeFileSync::DeletionPolicy value, TiXmlElement* parent) { - if (value == xmlAccess::ON_ERROR_IGNORE) - addXmlElement(parent, name, std::string("Ignore")); - else if (value == xmlAccess::ON_ERROR_EXIT) - addXmlElement(parent, name, std::string("Exit")); - else if (value == xmlAccess::ON_ERROR_POPUP) - addXmlElement(parent, name, std::string("Popup")); - else - assert(false); + switch (value) + { + case FreeFileSync::DELETE_PERMANENTLY: + xmlAccess::addXmlElement(name, std::string("DeletePermanently"), parent); + break; + case FreeFileSync::MOVE_TO_RECYCLE_BIN: + xmlAccess::addXmlElement(name, std::string("MoveToRecycleBin"), parent); + break; + case FreeFileSync::MOVE_TO_CUSTOM_DIRECTORY: + xmlAccess::addXmlElement(name, std::string("MoveToCustomDirectory"), parent); + break; + } } -void addXmlElementTable(TiXmlElement* parent, const std::string& name, const std::vector<wxString>& input) +void addXmlAttribute(const std::string& name, const xmlAccess::ColumnTypes value, TiXmlElement* node) { - for (std::vector<wxString>::const_iterator i = input.begin(); i != input.end(); ++i) - addXmlElement(parent, name, std::string(i->ToUTF8())); + xmlAccess::addXmlAttribute(name, static_cast<int>(value), node); } -bool XmlConfigOutput::writeXmlMainConfig(const MainConfiguration& mainCfg, const std::vector<FolderPair>& directoryPairs) +bool writeXmlMainConfig(const MainConfiguration& mainCfg, const std::vector<FolderPair>& directoryPairs, TiXmlDocument& doc) { TiXmlElement* root = doc.RootElement(); if (!root) return false; @@ -790,7 +519,7 @@ bool XmlConfigOutput::writeXmlMainConfig(const MainConfiguration& mainCfg, const settings->LinkEndChild(cmpSettings); //write compare algorithm - addXmlElement(cmpSettings, "Variant", mainCfg.compareVar); + ::addXmlElement("Variant", mainCfg.compareVar, cmpSettings); //write folder pair(s) TiXmlElement* folders = new TiXmlElement("Folders"); @@ -802,8 +531,8 @@ bool XmlConfigOutput::writeXmlMainConfig(const MainConfiguration& mainCfg, const TiXmlElement* folderPair = new TiXmlElement("Pair"); folders->LinkEndChild(folderPair); - addXmlElement(folderPair, "Left", std::string(wxString(i->leftDirectory.c_str()).ToUTF8())); - addXmlElement(folderPair, "Right", std::string(wxString(i->rightDirectory.c_str()).ToUTF8())); + xmlAccess::addXmlElement("Left", wxString(i->leftDirectory.c_str()), folderPair); + xmlAccess::addXmlElement("Right", wxString(i->rightDirectory.c_str()), folderPair); } //########################################################### @@ -814,11 +543,11 @@ bool XmlConfigOutput::writeXmlMainConfig(const MainConfiguration& mainCfg, const TiXmlElement* syncConfig = new TiXmlElement("Directions"); syncSettings->LinkEndChild(syncConfig); - addXmlElement(syncConfig, "LeftOnly", mainCfg.syncConfiguration.exLeftSideOnly); - addXmlElement(syncConfig, "RightOnly", mainCfg.syncConfiguration.exRightSideOnly); - addXmlElement(syncConfig, "LeftNewer", mainCfg.syncConfiguration.leftNewer); - addXmlElement(syncConfig, "RightNewer", mainCfg.syncConfiguration.rightNewer); - addXmlElement(syncConfig, "Different", mainCfg.syncConfiguration.different); + ::addXmlElement(syncConfig, "LeftOnly", mainCfg.syncConfiguration.exLeftSideOnly); + ::addXmlElement(syncConfig, "RightOnly", mainCfg.syncConfiguration.exRightSideOnly); + ::addXmlElement(syncConfig, "LeftNewer", mainCfg.syncConfiguration.leftNewer); + ::addXmlElement(syncConfig, "RightNewer", mainCfg.syncConfiguration.rightNewer); + ::addXmlElement(syncConfig, "Different", mainCfg.syncConfiguration.different); //########################################################### TiXmlElement* miscSettings = new TiXmlElement("Miscellaneous"); @@ -828,22 +557,23 @@ bool XmlConfigOutput::writeXmlMainConfig(const MainConfiguration& mainCfg, const TiXmlElement* filter = new TiXmlElement("Filter"); miscSettings->LinkEndChild(filter); - addXmlElement(filter, "Active", mainCfg.filterIsActive); - addXmlElement(filter, "Include", std::string((mainCfg.includeFilter).ToUTF8())); - addXmlElement(filter, "Exclude", std::string((mainCfg.excludeFilter).ToUTF8())); + xmlAccess::addXmlElement("Active", mainCfg.filterIsActive, filter); + xmlAccess::addXmlElement("Include", mainCfg.includeFilter, filter); + xmlAccess::addXmlElement("Exclude", mainCfg.excludeFilter, filter); //other - addXmlElement(miscSettings, "UseRecycler", mainCfg.useRecycleBin); + addXmlElement("DeletionPolicy", mainCfg.handleDeletion, miscSettings); + xmlAccess::addXmlElement("CustomDeletionFolder", mainCfg.customDeletionDirectory, miscSettings); //########################################################### return true; } -bool XmlConfigOutput::writeXmlGuiConfig(const xmlAccess::XmlGuiConfig& inputCfg) +bool writeXmlGuiConfig(const xmlAccess::XmlGuiConfig& inputCfg, TiXmlDocument& doc) { //write main config - if (!writeXmlMainConfig(inputCfg.mainCfg, inputCfg.directoryPairs)) + if (!writeXmlMainConfig(inputCfg.mainCfg, inputCfg.directoryPairs, doc)) return false; //write GUI specific config @@ -853,18 +583,20 @@ bool XmlConfigOutput::writeXmlGuiConfig(const xmlAccess::XmlGuiConfig& inputCfg) TiXmlElement* guiConfig = new TiXmlElement("GuiConfig"); root->LinkEndChild(guiConfig); - addXmlElement(guiConfig, "HideFiltered", inputCfg.hideFilteredElements); - addXmlElement(guiConfig, "IgnoreErrors", inputCfg.ignoreErrors); - addXmlElement(guiConfig, "SyncPreviewActive", inputCfg.syncPreviewEnabled); + xmlAccess::addXmlElement("HideFiltered", inputCfg.hideFilteredElements, guiConfig); + + ::addXmlElement("HandleError", inputCfg.ignoreErrors ? xmlAccess::ON_ERROR_IGNORE : xmlAccess::ON_ERROR_POPUP, guiConfig); + + xmlAccess::addXmlElement("SyncPreviewActive", inputCfg.syncPreviewEnabled, guiConfig); return true; } -bool XmlConfigOutput::writeXmlBatchConfig(const xmlAccess::XmlBatchConfig& inputCfg) +bool writeXmlBatchConfig(const xmlAccess::XmlBatchConfig& inputCfg, TiXmlDocument& doc) { //write main config - if (!writeXmlMainConfig(inputCfg.mainCfg, inputCfg.directoryPairs)) + if (!writeXmlMainConfig(inputCfg.mainCfg, inputCfg.directoryPairs, doc)) return false; //write GUI specific config @@ -874,15 +606,15 @@ bool XmlConfigOutput::writeXmlBatchConfig(const xmlAccess::XmlBatchConfig& input TiXmlElement* batchConfig = new TiXmlElement("BatchConfig"); root->LinkEndChild(batchConfig); - addXmlElement(batchConfig, "Silent", inputCfg.silent); - addXmlElement(batchConfig, "LogfileDirectory", std::string(inputCfg.logFileDirectory.ToUTF8())); - addXmlElement(batchConfig, "HandleError", inputCfg.handleError); + xmlAccess::addXmlElement("Silent", inputCfg.silent, batchConfig); + xmlAccess::addXmlElement("LogfileDirectory", inputCfg.logFileDirectory, batchConfig); + ::addXmlElement("HandleError", inputCfg.handleError, batchConfig); return true; } -bool XmlConfigOutput::writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& inputCfg) +bool writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& inputCfg, TiXmlDocument& doc) { TiXmlElement* root = doc.RootElement(); if (!root) return false; @@ -893,47 +625,38 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& root->LinkEndChild(global); //program language - addXmlElement(global, "Language", inputCfg.programLanguage); + xmlAccess::addXmlElement("Language", inputCfg.programLanguage, global); //max. allowed file time deviation - addXmlElement(global, "FileTimeTolerance", int(inputCfg.fileTimeTolerance)); + xmlAccess::addXmlElement("FileTimeTolerance", inputCfg.fileTimeTolerance, global); //ignore +/- 1 hour due to DST change - addXmlElement(global, "IgnoreOneHourDifference", inputCfg.ignoreOneHourDiff); + xmlAccess::addXmlElement("IgnoreOneHourDifference", inputCfg.ignoreOneHourDiff, global); //traverse into symbolic links (to folders) - addXmlElement(global, "TraverseDirectorySymlinks", inputCfg.traverseDirectorySymlinks); + xmlAccess::addXmlElement("TraverseDirectorySymlinks", inputCfg.traverseDirectorySymlinks, global); //copy symbolic links to files - addXmlElement(global, "CopyFileSymlinks", inputCfg.copyFileSymlinks); + xmlAccess::addXmlElement("CopyFileSymlinks", inputCfg.copyFileSymlinks, global); //last update check - addXmlElement(global, "LastCheckForUpdates", inputCfg.lastUpdateCheck); + xmlAccess::addXmlElement("LastCheckForUpdates", inputCfg.lastUpdateCheck, global); //warnings TiXmlElement* warnings = new TiXmlElement("Warnings"); global->LinkEndChild(warnings); //warning: dependent folders - addXmlElement(warnings, "CheckForDependentFolders", inputCfg.warnings.warningDependentFolders); + xmlAccess::addXmlElement("CheckForDependentFolders", inputCfg.warnings.warningDependentFolders, warnings); //significant difference check - addXmlElement(warnings, "CheckForSignificantDifference", inputCfg.warnings.warningSignificantDifference); + xmlAccess::addXmlElement("CheckForSignificantDifference", inputCfg.warnings.warningSignificantDifference, warnings); //check free disk space - addXmlElement(warnings, "CheckForFreeDiskSpace", inputCfg.warnings.warningNotEnoughDiskSpace); + xmlAccess::addXmlElement("CheckForFreeDiskSpace", inputCfg.warnings.warningNotEnoughDiskSpace, warnings); //check for unresolved conflicts - addXmlElement(warnings, "CheckForUnresolvedConflicts", inputCfg.warnings.warningUnresolvedConflicts); - - //check for very old dates or dates in the future - addXmlElement(warnings, "CheckForInvalidFileDate", inputCfg.warnings.warningInvalidDate); - - //check for changed files with same modification date - addXmlElement(warnings, "SameDateDifferentFileSize", inputCfg.warnings.warningSameDateDiffSize); - - //check for files that have a difference in file modification date below 1 hour when DST check is active - addXmlElement(warnings, "FileChangeWithinHour", inputCfg.warnings.warningDSTChangeWithinHour); + xmlAccess::addXmlElement("CheckForUnresolvedConflicts", inputCfg.warnings.warningUnresolvedConflicts, warnings); //################################################################### @@ -948,24 +671,27 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& windows->LinkEndChild(mainWindow); //window size - addXmlElement(mainWindow, "Width", inputCfg.gui.widthNotMaximized); - addXmlElement(mainWindow, "Height", inputCfg.gui.heightNotMaximized); + xmlAccess::addXmlElement("Width", inputCfg.gui.widthNotMaximized, mainWindow); + xmlAccess::addXmlElement("Height", inputCfg.gui.heightNotMaximized, mainWindow); //window position - addXmlElement(mainWindow, "PosX", inputCfg.gui.posXNotMaximized); - addXmlElement(mainWindow, "PosY", inputCfg.gui.posYNotMaximized); - addXmlElement(mainWindow, "Maximized", inputCfg.gui.isMaximized); + xmlAccess::addXmlElement("PosX", inputCfg.gui.posXNotMaximized, mainWindow); + xmlAccess::addXmlElement("PosY", inputCfg.gui.posYNotMaximized, mainWindow); + xmlAccess::addXmlElement("Maximized", inputCfg.gui.isMaximized, mainWindow); - addXmlElement(mainWindow, "ManualDeletionOnBothSides", inputCfg.gui.deleteOnBothSides); - addXmlElement(mainWindow, "ManualDeletionUseRecycler", inputCfg.gui.useRecyclerForManualDeletion); - addXmlElement(mainWindow, "ShowFileIconsLeft", inputCfg.gui.showFileIconsLeft); - addXmlElement(mainWindow, "ShowFileIconsRight", inputCfg.gui.showFileIconsRight); - addXmlElement(mainWindow, "PopupOnConfigChange", inputCfg.gui.popupOnConfigChange); - addXmlElement(mainWindow, "SummaryBeforeSync", inputCfg.gui.showSummaryBeforeSync); + xmlAccess::addXmlElement("ManualDeletionOnBothSides", inputCfg.gui.deleteOnBothSides, mainWindow); + xmlAccess::addXmlElement("ManualDeletionUseRecycler", inputCfg.gui.useRecyclerForManualDeletion, mainWindow); + xmlAccess::addXmlElement("ShowFileIconsLeft", inputCfg.gui.showFileIconsLeft, mainWindow); + xmlAccess::addXmlElement("ShowFileIconsRight", inputCfg.gui.showFileIconsRight, mainWindow); + xmlAccess::addXmlElement("PopupOnConfigChange", inputCfg.gui.popupOnConfigChange, mainWindow); + xmlAccess::addXmlElement("SummaryBeforeSync", inputCfg.gui.showSummaryBeforeSync, mainWindow); //write column attributes TiXmlElement* leftColumn = new TiXmlElement("LeftColumns"); mainWindow->LinkEndChild(leftColumn); + + xmlAccess::addXmlAttribute("AutoAdjust", inputCfg.gui.autoAdjustColumnsLeft, leftColumn); + xmlAccess::ColumnAttributes columnAtrribLeftCopy = inputCfg.gui.columnAttribLeft; //can't change const vector sort(columnAtrribLeftCopy.begin(), columnAtrribLeftCopy.end(), xmlAccess::sortByPositionOnly); for (unsigned int i = 0; i < columnAtrribLeftCopy.size(); ++i) @@ -974,14 +700,16 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& 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("Width", colAttrib.width); + addXmlAttribute("Type", colAttrib.type, subElement); + xmlAccess::addXmlAttribute("Visible", colAttrib.visible, subElement); + xmlAccess::addXmlAttribute("Width", colAttrib.width, subElement); } TiXmlElement* rightColumn = new TiXmlElement("RightColumns"); mainWindow->LinkEndChild(rightColumn); + + xmlAccess::addXmlAttribute("AutoAdjust", inputCfg.gui.autoAdjustColumnsRight, rightColumn); + xmlAccess::ColumnAttributes columnAtrribRightCopy = inputCfg.gui.columnAttribRight; sort(columnAtrribRightCopy.begin(), columnAtrribRightCopy.end(), xmlAccess::sortByPositionOnly); for (unsigned int i = 0; i < columnAtrribRightCopy.size(); ++i) @@ -990,10 +718,9 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& 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("Width", colAttrib.width); + addXmlAttribute("Type", colAttrib.type, subElement); + xmlAccess::addXmlAttribute("Visible", colAttrib.visible, subElement); + xmlAccess::addXmlAttribute("Width", colAttrib.width, subElement); } //write folder history elements @@ -1002,23 +729,23 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& TiXmlElement* historyRight = new TiXmlElement("FolderHistoryRight"); mainWindow->LinkEndChild(historyRight); - historyLeft->SetAttribute("MaximumSize", globalFunctions::numberToString(inputCfg.gui.folderHistLeftMax)); - addXmlElementTable(historyLeft, "Folder", inputCfg.gui.folderHistoryLeft); + xmlAccess::addXmlAttribute("MaximumSize", inputCfg.gui.folderHistLeftMax, historyLeft); + xmlAccess::addXmlAttribute("MaximumSize", inputCfg.gui.folderHistRightMax, historyRight); - historyRight->SetAttribute("MaximumSize", globalFunctions::numberToString(inputCfg.gui.folderHistRightMax)); - addXmlElementTable(historyRight, "Folder", inputCfg.gui.folderHistoryRight); + xmlAccess::addXmlElement("Folder", inputCfg.gui.folderHistoryLeft, historyLeft); + xmlAccess::addXmlElement("Folder", inputCfg.gui.folderHistoryRight, historyRight); - addXmlElement(mainWindow, "SelectedTabBottomLeft", inputCfg.gui.selectedTabBottomLeft); + xmlAccess::addXmlElement("SelectedTabBottomLeft", inputCfg.gui.selectedTabBottomLeft, mainWindow); //commandline for file manager integration - addXmlElement(gui, "FileManager", std::string((inputCfg.gui.commandLineFileManager).ToUTF8())); + xmlAccess::addXmlElement("FileManager", inputCfg.gui.commandLineFileManager, gui); //write config file history TiXmlElement* cfgHistory = new TiXmlElement("ConfigHistory"); gui->LinkEndChild(cfgHistory); - cfgHistory->SetAttribute("MaximumSize", globalFunctions::numberToString(inputCfg.gui.cfgHistoryMax)); - addXmlElementTable(cfgHistory, "File", inputCfg.gui.cfgFileHistory); + xmlAccess::addXmlAttribute("MaximumSize", inputCfg.gui.cfgHistoryMax, cfgHistory); + xmlAccess::addXmlElement("File", inputCfg.gui.cfgFileHistory, cfgHistory); //################################################################### //write global batch settings @@ -1032,98 +759,13 @@ bool XmlConfigOutput::writeXmlGlobalSettings(const xmlAccess::XmlGlobalSettings& int xmlAccess::retrieveSystemLanguage() { - const int lang = wxLocale::GetSystemLanguage(); - - switch (lang) //map language dialects - { - //variants of wxLANGUAGE_GERMAN - case wxLANGUAGE_GERMAN_AUSTRIAN: - case wxLANGUAGE_GERMAN_BELGIUM: - case wxLANGUAGE_GERMAN_LIECHTENSTEIN: - case wxLANGUAGE_GERMAN_LUXEMBOURG: - case wxLANGUAGE_GERMAN_SWISS: - return wxLANGUAGE_GERMAN; - - //variants of wxLANGUAGE_FRENCH - case wxLANGUAGE_FRENCH_BELGIAN: - case wxLANGUAGE_FRENCH_CANADIAN: - case wxLANGUAGE_FRENCH_LUXEMBOURG: - case wxLANGUAGE_FRENCH_MONACO: - case wxLANGUAGE_FRENCH_SWISS: - return wxLANGUAGE_FRENCH; - - //variants of wxLANGUAGE_DUTCH - case wxLANGUAGE_DUTCH_BELGIAN: - return wxLANGUAGE_DUTCH; - - //variants of wxLANGUAGE_ITALIAN - case wxLANGUAGE_ITALIAN_SWISS: - return wxLANGUAGE_ITALIAN; - - //variants of wxLANGUAGE_CHINESE_SIMPLIFIED - case wxLANGUAGE_CHINESE: - case wxLANGUAGE_CHINESE_TRADITIONAL: - case wxLANGUAGE_CHINESE_HONGKONG: - case wxLANGUAGE_CHINESE_MACAU: - case wxLANGUAGE_CHINESE_SINGAPORE: - case wxLANGUAGE_CHINESE_TAIWAN: - return wxLANGUAGE_CHINESE_SIMPLIFIED; - - //variants of wxLANGUAGE_RUSSIAN - case wxLANGUAGE_RUSSIAN_UKRAINE: - return wxLANGUAGE_RUSSIAN; - - //variants of wxLANGUAGE_SPANISH - case wxLANGUAGE_SPANISH_ARGENTINA: - case wxLANGUAGE_SPANISH_BOLIVIA: - case wxLANGUAGE_SPANISH_CHILE: - case wxLANGUAGE_SPANISH_COLOMBIA: - case wxLANGUAGE_SPANISH_COSTA_RICA: - case wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC: - case wxLANGUAGE_SPANISH_ECUADOR: - case wxLANGUAGE_SPANISH_EL_SALVADOR: - case wxLANGUAGE_SPANISH_GUATEMALA: - case wxLANGUAGE_SPANISH_HONDURAS: - case wxLANGUAGE_SPANISH_MEXICAN: - case wxLANGUAGE_SPANISH_MODERN: - case wxLANGUAGE_SPANISH_NICARAGUA: - case wxLANGUAGE_SPANISH_PANAMA: - case wxLANGUAGE_SPANISH_PARAGUAY: - case wxLANGUAGE_SPANISH_PERU: - case wxLANGUAGE_SPANISH_PUERTO_RICO: - case wxLANGUAGE_SPANISH_URUGUAY: - case wxLANGUAGE_SPANISH_US: - case wxLANGUAGE_SPANISH_VENEZUELA: - return wxLANGUAGE_SPANISH; - - //case wxLANGUAGE_JAPANESE: - //case wxLANGUAGE_POLISH: - //case wxLANGUAGE_SLOVENIAN: - //case wxLANGUAGE_HUNGARIAN: - //case wxLANGUAGE_PORTUGUESE: - //case wxLANGUAGE_PORTUGUESE_BRAZILIAN: - - default: - return lang; - } + return wxLocale::GetSystemLanguage(); } -bool xmlAccess::supportForSymbolicLinks() +bool xmlAccess::recycleBinAvailable() { -#ifdef FFS_WIN - OSVERSIONINFO osvi; - ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - - //symbolic links are supported starting with Vista - if (GetVersionEx(&osvi)) - return osvi.dwMajorVersion > 5; //XP has majorVersion == 5, minorVersion == 1, Vista majorVersion == 6 - - return false; -#elif defined FFS_LINUX - return true; -#endif + return FreeFileSync::recycleBinExists(); } @@ -1133,7 +775,4 @@ void xmlAccess::WarningMessages::resetWarnings() warningSignificantDifference = true; warningNotEnoughDiskSpace = true; warningUnresolvedConflicts = true; - warningInvalidDate = true; - warningSameDateDiffSize = true; - warningDSTChangeWithinHour = true; } diff --git a/library/processXml.h b/library/processXml.h index 15972289..9fad5cd7 100644 --- a/library/processXml.h +++ b/library/processXml.h @@ -2,7 +2,6 @@ #define PROCESSXML_H_INCLUDED #include "../structures.h" -#include "fileHandling.h" namespace xmlAccess { @@ -13,14 +12,6 @@ namespace xmlAccess ON_ERROR_EXIT }; - enum XmlType - { - XML_GUI_CONFIG, - XML_BATCH_CONFIG, - XML_GLOBAL_SETTINGS, - XML_OTHER - }; - enum ColumnTypes { DIRECTORY, @@ -30,7 +21,7 @@ namespace xmlAccess SIZE, DATE }; - const unsigned COLUMN_TYPE_COUNT = 6; + const unsigned int COLUMN_TYPE_COUNT = 6; struct ColumnAttrib { @@ -41,7 +32,6 @@ namespace xmlAccess }; typedef std::vector<ColumnAttrib> ColumnAttributes; - XmlType getXmlType(const wxString& filename); //--------------------------------------------------------------------- struct XmlGuiConfig @@ -60,11 +50,11 @@ namespace xmlAccess bool operator==(const XmlGuiConfig& other) const { - return mainCfg == other.mainCfg && - directoryPairs == other.directoryPairs && - hideFilteredElements == other.hideFilteredElements && - ignoreErrors == other.ignoreErrors && - syncPreviewEnabled == other.syncPreviewEnabled; + return mainCfg == other.mainCfg && + directoryPairs == other.directoryPairs && + hideFilteredElements == other.hideFilteredElements && + ignoreErrors == other.ignoreErrors && + syncPreviewEnabled == other.syncPreviewEnabled; } bool operator!=(const XmlGuiConfig& other) const @@ -87,7 +77,7 @@ namespace xmlAccess }; int retrieveSystemLanguage(); - bool supportForSymbolicLinks(); + bool recycleBinAvailable(); struct WarningMessages @@ -103,9 +93,6 @@ namespace xmlAccess bool warningSignificantDifference; bool warningNotEnoughDiskSpace; bool warningUnresolvedConflicts; - bool warningInvalidDate; - bool warningSameDateDiffSize; - bool warningDSTChangeWithinHour; }; @@ -118,7 +105,7 @@ namespace xmlAccess fileTimeTolerance(2), //default 2s: FAT vs NTFS ignoreOneHourDiff(true), traverseDirectorySymlinks(false), - copyFileSymlinks(supportForSymbolicLinks()), + copyFileSymlinks(true), lastUpdateCheck(0) {} int programLanguage; @@ -126,7 +113,7 @@ namespace xmlAccess 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 + long lastUpdateCheck; //time of last update check WarningMessages warnings; @@ -139,17 +126,19 @@ namespace xmlAccess posXNotMaximized(wxDefaultCoord), posYNotMaximized(wxDefaultCoord), isMaximized(false), + autoAdjustColumnsLeft(false), + autoAdjustColumnsRight(false), #ifdef FFS_WIN commandLineFileManager(wxT("explorer /select, %name")), #elif defined FFS_LINUX - commandLineFileManager(wxT("konqueror \"%path\"")), + commandLineFileManager(wxT("konqueror \"%dir\"")), #endif cfgHistoryMax(10), folderHistLeftMax(12), folderHistRightMax(12), selectedTabBottomLeft(0), deleteOnBothSides(false), - useRecyclerForManualDeletion(FreeFileSync::recycleBinExists()), //enable if OS supports it; else user will have to activate first and then get an error message + useRecyclerForManualDeletion(recycleBinAvailable()), //enable if OS supports it; else user will have to activate first and then get an error message showFileIconsLeft(true), showFileIconsRight(true), popupOnConfigChange(true), @@ -164,6 +153,9 @@ namespace xmlAccess ColumnAttributes columnAttribLeft; ColumnAttributes columnAttribRight; + bool autoAdjustColumnsLeft; + bool autoAdjustColumnsRight; + wxString commandLineFileManager; std::vector<wxString> cfgFileHistory; @@ -214,15 +206,13 @@ namespace xmlAccess return a.position < b.position; } + void readGuiConfig( const wxString& filename, XmlGuiConfig& config); //throw (xmlAccess::XmlError); + void readBatchConfig(const wxString& filename, XmlBatchConfig& config); //throw (xmlAccess::XmlError); + void readGlobalSettings( XmlGlobalSettings& config); //throw (xmlAccess::XmlError); - XmlGuiConfig readGuiConfig(const wxString& filename); - XmlBatchConfig readBatchConfig(const wxString& filename); - XmlGlobalSettings readGlobalSettings(); //used for both GUI and batch mode, independent from configuration instance - - void writeGuiConfig(const wxString& filename, const XmlGuiConfig& outputCfg); - void writeBatchConfig(const wxString& filename, const XmlBatchConfig& outputCfg); - void writeGlobalSettings(const XmlGlobalSettings& outputCfg); - + void writeGuiConfig( const XmlGuiConfig& outputCfg, const wxString& filename); //throw (xmlAccess::XmlError); + void writeBatchConfig( const XmlBatchConfig& outputCfg, const wxString& filename); //throw (xmlAccess::XmlError); + void writeGlobalSettings(const XmlGlobalSettings& outputCfg); //throw (xmlAccess::XmlError); } diff --git a/library/resources.cpp b/library/resources.cpp index 38f2a051..3e7b5a4e 100644 --- a/library/resources.cpp +++ b/library/resources.cpp @@ -4,8 +4,9 @@ #include <wx/image.h> #include <wx/icon.h> #include <wx/mstream.h> -#include "globalFunctions.h" -#include "../structures.h" +#include "../shared/globalFunctions.h" +//#include "../shared/systemFunctions.h" +#include "../shared/standardPaths.h" const GlobalResources& GlobalResources::getInstance() @@ -98,16 +99,20 @@ GlobalResources::GlobalResources() bitmapResource[wxT("batch_small.png")] = (bitmapBatchSmall = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("move up.png")] = (bitmapMoveUp = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("move down.png")] = (bitmapMoveDown = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("checkbox true.png")] = (bitmapCheckBoxTrue = new wxBitmap(wxNullBitmap)); - bitmapResource[wxT("checkbox false.png")] = (bitmapCheckBoxFalse = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("checkbox_true.png")] = (bitmapCheckBoxTrue = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("checkbox_true_focus.png")] = (bitmapCheckBoxTrueFocus = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("checkbox_false.png")] = (bitmapCheckBoxFalse = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("checkbox_false_focus.png")] = (bitmapCheckBoxFalseFocus = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("settings.png")] = (bitmapSettings = new wxBitmap(wxNullBitmap)); 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("cmpConfig.png")] = (bitmapCmpCfg = 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("czechRep.png")] = (bitmapCzechRep = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("china.png")] = (bitmapChina = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("holland.png")] = (bitmapHolland = new wxBitmap(wxNullBitmap)); bitmapResource[wxT("england.png")] = (bitmapEngland = new wxBitmap(wxNullBitmap)); @@ -120,8 +125,16 @@ GlobalResources::GlobalResources() bitmapResource[wxT("portugal.png")] = (bitmapPortugal = new wxBitmap(wxNullBitmap)); 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("russia.png")] = (bitmapRussia = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("spain.png")] = (bitmapSpain = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("russia.png")] = (bitmapRussia = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncCreateLeftAct.png")] = (bitmapSyncCreateLeftAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncCreateLeftDeact.png")] = (bitmapSyncCreateLeftDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncCreateRightAct.png")] = (bitmapSyncCreateRightAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncCreateRightDeact.png")] = (bitmapSyncCreateRightDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDeleteLeftAct.png")] = (bitmapSyncDeleteLeftAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDeleteLeftDeact.png")] = (bitmapSyncDeleteLeftDeact = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDeleteRightAct.png")] = (bitmapSyncDeleteRightAct = new wxBitmap(wxNullBitmap)); + bitmapResource[wxT("syncDeleteRightDeact.png")] = (bitmapSyncDeleteRightDeact = 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)); @@ -191,7 +204,7 @@ void loadAnimFromZip(wxZipInputStream& zipInput, wxAnimation* animation) void GlobalResources::load() const { - wxFileInputStream input(FreeFileSync::getInstallationDir() + FreeFileSync::FILE_NAME_SEPARATOR + wxT("Resources.dat")); + wxFFileInputStream input(FreeFileSync::getInstallationDir() + globalFunctions::FILE_NAME_SEPARATOR + wxT("Resources.dat")); if (input.IsOk()) //if not... we don't want to react too harsh here { //activate support for .png files @@ -199,10 +212,13 @@ void GlobalResources::load() const wxZipInputStream resourceFile(input); - wxZipEntry* entry = NULL; std::map<wxString, wxBitmap*>::iterator bmp; - while ((entry = resourceFile.GetNextEntry())) + while (true) { + std::auto_ptr<wxZipEntry> entry(resourceFile.GetNextEntry()); + if (entry.get() == NULL) + break; + const wxString name = entry->GetName(); //search if entry is available in map @@ -222,3 +238,13 @@ void GlobalResources::load() const *programIcon = wxIcon(FreeFileSync_xpm); #endif } + + +const wxBitmap& GlobalResources::getImageByName(const wxString& imageName) const +{ + std::map<wxString, wxBitmap*>::const_iterator bmp = bitmapResource.find(imageName); + if (bmp != bitmapResource.end()) + return *bmp->second; + else + return wxNullBitmap; +} diff --git a/library/resources.h b/library/resources.h index 1ce7d20e..5f4e51f0 100644 --- a/library/resources.h +++ b/library/resources.h @@ -12,6 +12,8 @@ class GlobalResources public: static const GlobalResources& getInstance(); + const wxBitmap& getImageByName(const wxString& imageName) const; + //image resource objects wxBitmap* bitmapArrowLeft; wxBitmap* bitmapArrowRight; @@ -94,15 +96,19 @@ public: wxBitmap* bitmapMoveUp; wxBitmap* bitmapMoveDown; wxBitmap* bitmapCheckBoxTrue; + wxBitmap* bitmapCheckBoxTrueFocus; wxBitmap* bitmapCheckBoxFalse; + wxBitmap* bitmapCheckBoxFalseFocus; wxBitmap* bitmapSettings; wxBitmap* bitmapSettingsSmall; wxBitmap* bitmapRecycler; wxBitmap* bitmapShift; wxBitmap* bitmapSyncCfg; + wxBitmap* bitmapCmpCfg; wxBitmap* bitmapPreview; wxBitmap* bitmapPreviewDisabled; wxBitmap* bitmapQuestion; + wxBitmap* bitmapCzechRep; wxBitmap* bitmapChina; wxBitmap* bitmapHolland; wxBitmap* bitmapEngland; @@ -117,6 +123,14 @@ public: wxBitmap* bitmapSlovakia; wxBitmap* bitmapSpain; wxBitmap* bitmapRussia; + wxBitmap* bitmapSyncCreateLeftAct; + wxBitmap* bitmapSyncCreateLeftDeact; + wxBitmap* bitmapSyncCreateRightAct; + wxBitmap* bitmapSyncCreateRightDeact; + wxBitmap* bitmapSyncDeleteLeftAct; + wxBitmap* bitmapSyncDeleteLeftDeact; + wxBitmap* bitmapSyncDeleteRightAct; + wxBitmap* bitmapSyncDeleteRightDeact; wxBitmap* bitmapSyncDirLeftAct; wxBitmap* bitmapSyncDirLeftDeact; wxBitmap* bitmapSyncDirRightAct; diff --git a/library/statistics.cpp b/library/statistics.cpp index f2506da8..f317c114 100644 --- a/library/statistics.cpp +++ b/library/statistics.cpp @@ -1,9 +1,10 @@ #include "statistics.h" #include <wx/ffile.h> -#include "globalFunctions.h" +#include "../shared/globalFunctions.h" #include "statusHandler.h" #include "../algorithm.h" +#include <wx/intl.h> #include <limits> #include <wx/stopwatch.h> diff --git a/library/statusHandler.h b/library/statusHandler.h index fe64f3cd..d4163d2f 100644 --- a/library/statusHandler.h +++ b/library/statusHandler.h @@ -59,9 +59,9 @@ public: //error handling: - virtual ErrorHandler::Response reportError(const Zstring& errorMessage) = 0; //recoverable error situation - virtual void reportFatalError(const Zstring& errorMessage) = 0; //non-recoverable error situation, implement abort! - virtual void reportWarning(const Zstring& warningMessage, bool& dontShowAgain) = 0; + virtual ErrorHandler::Response reportError(const wxString& errorMessage) = 0; //recoverable error situation + virtual void reportFatalError(const wxString& errorMessage) = 0; //non-recoverable error situation, implement abort! + virtual void reportWarning(const wxString& warningMessage, bool& warningActive) = 0; private: virtual void abortThisProcess() = 0; |