summaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
Diffstat (limited to 'library')
-rw-r--r--library/Batch.icobin139831 -> 0 bytes
-rw-r--r--library/FreeFileSync.icobin132167 -> 0 bytes
-rw-r--r--library/SyncDB.icobin145378 -> 0 bytes
-rw-r--r--library/binary.cpp125
-rw-r--r--library/binary.h28
-rw-r--r--library/cmp_filetime.h64
-rw-r--r--library/custom_grid.cpp2404
-rw-r--r--library/custom_grid.h370
-rw-r--r--library/db_file.cpp598
-rw-r--r--library/db_file.h31
-rw-r--r--library/detect_renaming.cpp285
-rw-r--r--library/detect_renaming.h26
-rw-r--r--library/dir_exist_async.h35
-rw-r--r--library/dir_lock.cpp599
-rw-r--r--library/dir_lock.h35
-rw-r--r--library/error_log.cpp96
-rw-r--r--library/error_log.h50
-rw-r--r--library/hard_filter.cpp368
-rw-r--r--library/hard_filter.h279
-rw-r--r--library/icon_buffer.cpp613
-rw-r--r--library/icon_buffer.h50
-rw-r--r--library/lock_holder.h58
-rw-r--r--library/norm_filter.h98
-rw-r--r--library/parallel_scan.cpp611
-rw-r--r--library/parallel_scan.h74
-rw-r--r--library/process_xml.cpp1172
-rw-r--r--library/process_xml.h283
-rw-r--r--library/resources.cpp122
-rw-r--r--library/resources.h45
-rw-r--r--library/soft_filter.h121
-rw-r--r--library/statistics.cpp378
-rw-r--r--library/statistics.h83
-rw-r--r--library/status_handler.cpp34
-rw-r--r--library/status_handler.h102
34 files changed, 0 insertions, 9237 deletions
diff --git a/library/Batch.ico b/library/Batch.ico
deleted file mode 100644
index 7b33067a..00000000
--- a/library/Batch.ico
+++ /dev/null
Binary files differ
diff --git a/library/FreeFileSync.ico b/library/FreeFileSync.ico
deleted file mode 100644
index b87789a7..00000000
--- a/library/FreeFileSync.ico
+++ /dev/null
Binary files differ
diff --git a/library/SyncDB.ico b/library/SyncDB.ico
deleted file mode 100644
index eee91c14..00000000
--- a/library/SyncDB.ico
+++ /dev/null
Binary files differ
diff --git a/library/binary.cpp b/library/binary.cpp
deleted file mode 100644
index 1e043d33..00000000
--- a/library/binary.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#include "binary.h"
-#include "../shared/file_io.h"
-#include <vector>
-#include <wx/stopwatch.h>
-#include "../shared/int64.h"
-#include <boost/thread/tss.hpp>
-
-inline
-void setMinSize(std::vector<char>& buffer, size_t minSize)
-{
- if (buffer.size() < minSize) //this is similar to reserve(), but we need a "properly initialized" array here
- buffer.resize(minSize);
-}
-
-
-namespace
-{
-class BufferSize
-{
-public:
- BufferSize() : bufSize(BUFFER_SIZE_START) {}
-
- void inc()
- {
- if (bufSize < BUFFER_SIZE_MAX)
- bufSize *= 2;
- }
-
- void dec()
- {
- if (bufSize > BUFFER_SIZE_MIN)
- bufSize /= 2;
- }
-
- operator size_t() const { return bufSize; }
-
-private:
- static const size_t BUFFER_SIZE_MIN = 128 * 1024;
- static const size_t BUFFER_SIZE_START = 512 * 1024; //512 kb seems to be a reasonable initial buffer size
- static const size_t BUFFER_SIZE_MAX = 16 * 1024 * 1024;
-
- /*Tests on Win7 x64 show that buffer size does NOT matter if files are located on different physical disks!
- Impact of buffer size when files are on same disk:
-
- buffer MB/s
- ------------
- 64 10
- 128 19
- 512 40
- 1024 48
- 2048 56
- 4096 56
- 8192 56
- */
-
- size_t bufSize;
-};
-}
-
-
-bool zen::filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, CompareCallback& callback)
-{
- FileInput file1(filename1); //throw FileError
- FileInput file2(filename2); //throw FileError
-
- static boost::thread_specific_ptr<std::vector<char>> cpyBuf1;
- static boost::thread_specific_ptr<std::vector<char>> cpyBuf2;
- if (!cpyBuf1.get())
- cpyBuf1.reset(new std::vector<char>());
- if (!cpyBuf2.get())
- cpyBuf2.reset(new std::vector<char>());
-
- std::vector<char>& memory1 = *cpyBuf1;
- std::vector<char>& memory2 = *cpyBuf2;
-
- BufferSize bufferSize;
- zen::UInt64 bytesCompared;
-
- wxLongLong lastDelayViolation = wxGetLocalTimeMillis();
-
- do
- {
- setMinSize(memory1, bufferSize);
- setMinSize(memory2, bufferSize);
-
- const wxLongLong startTime = wxGetLocalTimeMillis();
-
- const size_t length1 = file1.read(&memory1[0], bufferSize); //returns actual number of bytes read; throw FileError()
- const size_t length2 = file2.read(&memory2[0], bufferSize); //
-
- const wxLongLong stopTime = wxGetLocalTimeMillis();
-
- //-------- dynamically set buffer size to keep callback interval between 200 - 500ms ---------------------
- const wxLongLong loopTime = stopTime - startTime;
- if (loopTime < 200 && stopTime - lastDelayViolation > 2000) //avoid "flipping back": e.g. DVD-Roms read 32MB at once, so first read may be > 300 ms, but second one will be 0ms!
- {
- lastDelayViolation = stopTime;
- bufferSize.inc(); //practically no costs!
- }
- else if (loopTime > 500)
- {
- lastDelayViolation = stopTime;
- bufferSize.dec(); //
- }
- //------------------------------------------------------------------------------------------------
-
- if (length1 != length2 || ::memcmp(&memory1[0], &memory2[0], length1) != 0)
- return false;
-
- bytesCompared += length1 * 2;
- callback.updateCompareStatus(bytesCompared); //send progress updates
- }
- while (!file1.eof());
-
- if (!file2.eof()) //highly unlikely, but theoretically possible! (but then again, not in this context where both files have same size...)
- return false;
-
- return true;
-}
diff --git a/library/binary.h b/library/binary.h
deleted file mode 100644
index 4dbbcd45..00000000
--- a/library/binary.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#ifndef BINARY_H_INCLUDED
-#define BINARY_H_INCLUDED
-
-#include "../shared/zstring.h"
-#include "../shared/file_error.h"
-#include "../shared/int64.h"
-
-namespace zen
-{
-
-//callback functionality for status updates while comparing
-class CompareCallback
-{
-public:
- virtual ~CompareCallback() {}
- virtual void updateCompareStatus(zen::UInt64 totalBytesTransferred) = 0;
-};
-
-bool filesHaveSameContent(const Zstring& filename1, const Zstring& filename2, CompareCallback& callback); //throw FileError
-}
-
-#endif // BINARY_H_INCLUDED
diff --git a/library/cmp_filetime.h b/library/cmp_filetime.h
deleted file mode 100644
index 24b331c6..00000000
--- a/library/cmp_filetime.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef CMP_FILETIME_H_INCLUDED
-#define CMP_FILETIME_H_INCLUDED
-
-#include <wx/stopwatch.h>
-#include "../shared/int64.h"
-
-namespace zen
-{
-//---------------------------------------------------------------------------------------------------------------
-inline
-bool sameFileTime(const Int64& a, const Int64& b, size_t tolerance)
-{
- if (a < b)
- return b <= a + static_cast<int>(tolerance);
- else
- return a <= b + static_cast<int>(tolerance);
-}
-//---------------------------------------------------------------------------------------------------------------
-
-class CmpFileTime
-{
-public:
- CmpFileTime(size_t tolerance) : tolerance_(tolerance) {}
-
- enum Result
- {
- TIME_EQUAL,
- TIME_LEFT_NEWER,
- TIME_RIGHT_NEWER,
- TIME_LEFT_INVALID,
- TIME_RIGHT_INVALID
- };
-
- Result getResult(const Int64& lhs, const Int64& rhs) const
- {
- if (lhs == rhs)
- return TIME_EQUAL;
-
- //number of seconds since Jan 1st 1970 + 1 year (needn't be too precise)
- static const long oneYearFromNow = wxGetUTCTime() + 365 * 24 * 3600; //static in header: not a big deal in this case!
-
- //check for erroneous dates (but only if dates are not (EXACTLY) the same)
- if (lhs < 0 || lhs > oneYearFromNow) //earlier than Jan 1st 1970 or more than one year in future
- return TIME_LEFT_INVALID;
-
- if (rhs < 0 || rhs > oneYearFromNow)
- return TIME_RIGHT_INVALID;
-
- if (sameFileTime(lhs, rhs, tolerance_)) //last write time may differ by up to 2 seconds (NTFS vs FAT32)
- return TIME_EQUAL;
-
- //regular time comparison
- if (lhs < rhs)
- return TIME_RIGHT_NEWER;
- else
- return TIME_LEFT_NEWER;
- }
-
-private:
- const size_t tolerance_;
-};
-}
-
-#endif // CMP_FILETIME_H_INCLUDED
diff --git a/library/custom_grid.cpp b/library/custom_grid.cpp
deleted file mode 100644
index b4d7af41..00000000
--- a/library/custom_grid.cpp
+++ /dev/null
@@ -1,2404 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#include "custom_grid.h"
-#include "resources.h"
-#include <wx/dc.h>
-#include "../shared/util.h"
-#include "../shared/string_conv.h"
-#include "resources.h"
-#include <typeinfo>
-#include "../ui/grid_view.h"
-#include "../synchronization.h"
-#include "../shared/custom_tooltip.h"
-#include "../shared/i18n.h"
-#include <wx/dcclient.h>
-#include <wx/icon.h>
-#include <wx/tooltip.h>
-#include <wx/settings.h>
-#include "../shared/i18n.h"
-
-#ifdef FFS_WIN
-#include <wx/timer.h>
-#include "status_handler.h"
-#include <cmath>
-
-#elif defined FFS_LINUX
-#include <gtk/gtk.h>
-#endif
-
-using namespace zen;
-
-
-const size_t MIN_ROW_COUNT = 15;
-
-//class containing pure grid data: basically the same as wxGridStringTable, but adds cell formatting
-
-/*
-class hierarchy:
- CustomGridTable
- /|\
- ________________|________________
- | |
- CustomGridTableRim |
- /|\ |
- __________|__________ |
- | | |
-CustomGridTableLeft CustomGridTableRight CustomGridTableMiddle
-*/
-
-class CustomGridTable : public wxGridTableBase
-{
-public:
- CustomGridTable(int initialRows = 0, int initialCols = 0) : //note: initialRows/initialCols MUST match with GetNumberRows()/GetNumberCols() at initialization!!!
- wxGridTableBase(),
- gridDataView(NULL),
- lastNrRows(initialRows),
- lastNrCols(initialCols) {}
-
-
- virtual ~CustomGridTable() {}
-
-
- void setGridDataTable(const GridView* view)
- {
- this->gridDataView = view;
- }
-
-
- //###########################################################################
- //grid standard input output methods, redirected directly to gridData to improve performance
-
- virtual int GetNumberRows()
- {
- if (gridDataView)
- return static_cast<int>(std::max(gridDataView->rowsOnView(), MIN_ROW_COUNT));
- else
- return 0; //grid is initialized with zero number of rows
- }
-
-
- virtual bool IsEmptyCell(int row, int col)
- {
- return false; //avoid overlapping cells
-
- //return (GetValue(row, col) == wxEmptyString);
- }
-
-
- virtual void SetValue(int row, int col, const wxString& value)
- {
- assert (false); //should not be used, since values are retrieved directly from gridDataView
- }
-
- //update dimensions of grid: no need for InsertRows(), AppendRows(), DeleteRows() anymore!!!
- void updateGridSizes()
- {
- const int currentNrRows = GetNumberRows();
-
- if (lastNrRows < currentNrRows)
- {
- if (GetView())
- {
- wxGridTableMessage msg(this,
- wxGRIDTABLE_NOTIFY_ROWS_APPENDED,
- currentNrRows - lastNrRows);
-
- GetView()->ProcessTableMessage( msg );
- }
- }
- else if (lastNrRows > currentNrRows)
- {
- if (GetView())
- {
- wxGridTableMessage msg(this,
- wxGRIDTABLE_NOTIFY_ROWS_DELETED,
- 0,
- lastNrRows - currentNrRows);
-
- GetView()->ProcessTableMessage( msg );
- }
- }
- lastNrRows = currentNrRows;
-
- const int currentNrCols = GetNumberCols();
-
- if (lastNrCols < currentNrCols)
- {
- if (GetView())
- {
- wxGridTableMessage msg(this,
- wxGRIDTABLE_NOTIFY_COLS_APPENDED,
- currentNrCols - lastNrCols);
-
- GetView()->ProcessTableMessage( msg );
- }
- }
- else if (lastNrCols > currentNrCols)
- {
- if (GetView())
- {
- wxGridTableMessage msg(this,
- wxGRIDTABLE_NOTIFY_COLS_DELETED,
- 0,
- lastNrCols - currentNrCols);
-
- GetView()->ProcessTableMessage( msg );
- }
- }
- lastNrCols = currentNrCols;
- }
- //###########################################################################
-
-
- virtual wxGridCellAttr* GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind)
- {
- const std::pair<wxColour, wxColour> color = getRowColor(row);
-
- //add color to some rows
- wxGridCellAttr* result = wxGridTableBase::GetAttr(row, col, kind);
- if (result)
- {
- if (result->GetTextColour() == color.first &&
- result->GetBackgroundColour() == color.second)
- {
- return result;
- }
- else //grid attribute might be referenced by other elements, so clone it!
- {
- wxGridCellAttr* attr = result->Clone(); //attr has ref-count 1
- result->DecRef();
- result = attr;
- }
- }
- else
- result = new wxGridCellAttr; //created with ref-count 1
-
- result->SetTextColour (color.first);
- result->SetBackgroundColour(color.second);
-
- return result;
- }
-
-
- const FileSystemObject* getRawData(size_t row) const
- {
- if (gridDataView)
- return gridDataView->getObject(row); //returns NULL if request is not valid or not data found
-
- return NULL;
- }
-
-protected:
- static const wxColour COLOR_BLUE;
- static const wxColour COLOR_GREY;
- static const wxColour COLOR_ORANGE;
- static const wxColour COLOR_CMP_RED;
- static const wxColour COLOR_CMP_BLUE;
- static const wxColour COLOR_CMP_GREEN;
- static const wxColour COLOR_SYNC_BLUE;
- static const wxColour COLOR_SYNC_BLUE_LIGHT;
- static const wxColour COLOR_SYNC_GREEN;
- static const wxColour COLOR_SYNC_GREEN_LIGHT;
- static const wxColour COLOR_YELLOW;
- static const wxColour COLOR_YELLOW_LIGHT;
-
- const GridView* gridDataView; //(very fast) access to underlying grid data :)
-
-private:
- virtual const std::pair<wxColour, wxColour> getRowColor(int row) = 0; //rows that are filtered out are shown in different color: <foreground, background>
-
- int lastNrRows;
- int lastNrCols;
-};
-
-//see http://www.latiumsoftware.com/en/articles/00015.php#12 for "safe" colors
-const wxColour CustomGridTable::COLOR_ORANGE( 238, 201, 0);
-const wxColour CustomGridTable::COLOR_BLUE( 80, 110, 255);
-const wxColour CustomGridTable::COLOR_GREY( 212, 208, 200);
-const wxColour CustomGridTable::COLOR_CMP_RED( 249, 163, 165);
-const wxColour CustomGridTable::COLOR_CMP_BLUE( 144, 232, 246);
-const wxColour CustomGridTable::COLOR_CMP_GREEN( 147, 253, 159);
-const wxColour CustomGridTable::COLOR_SYNC_BLUE( 201, 203, 247);
-const wxColour CustomGridTable::COLOR_SYNC_BLUE_LIGHT(201, 225, 247);
-const wxColour CustomGridTable::COLOR_SYNC_GREEN(197, 248, 190);
-const wxColour CustomGridTable::COLOR_SYNC_GREEN_LIGHT(226, 248, 190);
-const wxColour CustomGridTable::COLOR_YELLOW( 247, 252, 62);
-const wxColour CustomGridTable::COLOR_YELLOW_LIGHT(253, 252, 169);
-
-
-class CustomGridTableRim : public CustomGridTable
-{
-public:
- virtual ~CustomGridTableRim() {}
-
- virtual int GetNumberCols()
- {
- return static_cast<int>(columnPositions.size());
- }
-
- virtual wxString GetColLabelValue( int col )
- {
- return CustomGridRim::getTypeName(getTypeAtPos(col));
- }
-
-
- void setupColumns(const std::vector<xmlAccess::ColumnTypes>& positions)
- {
- columnPositions = positions;
- updateGridSizes(); //add or remove columns
- }
-
-
- xmlAccess::ColumnTypes getTypeAtPos(size_t pos) const
- {
- if (pos < columnPositions.size())
- return columnPositions[pos];
- else
- return xmlAccess::DIRECTORY;
- }
-
- //get filename in order to retrieve the icon from it
- virtual Zstring getIconFile(size_t row) const = 0; //return "folder" if row points to a folder
-
-protected:
- template <SelectedSide side>
- wxString GetValueSub(int row, int col)
- {
- const FileSystemObject* fsObj = getRawData(row);
- if (fsObj)
- {
- struct GetValue : public FSObjectVisitor
- {
- GetValue(xmlAccess::ColumnTypes colType, const FileSystemObject& fso) : colType_(colType), fsObj_(fso) {}
- virtual void visit(const FileMapping& fileObj)
- {
- switch (colType_)
- {
- case xmlAccess::FULL_PATH:
- value = toWx(fileObj.getFullName<side>().BeforeLast(FILE_NAME_SEPARATOR));
- break;
- case xmlAccess::FILENAME: //filename
- value = toWx(fileObj.getShortName<side>());
- break;
- case xmlAccess::REL_PATH: //relative path
- value = toWx(fileObj.getObjRelativeName().BeforeLast(FILE_NAME_SEPARATOR)); //returns empty string if ch not found
- break;
- case xmlAccess::DIRECTORY:
- value = toWx(fileObj.getBaseDirPf<side>());
- break;
- case xmlAccess::SIZE: //file size
- if (!fsObj_.isEmpty<side>())
- value = zen::toStringSep(fileObj.getFileSize<side>());
- break;
- case xmlAccess::DATE: //date
- if (!fsObj_.isEmpty<side>())
- value = zen::utcTimeToLocalString(fileObj.getLastWriteTime<side>());
- break;
- case xmlAccess::EXTENSION: //file extension
- value = toWx(fileObj.getExtension<side>());
- break;
- }
- }
-
- virtual void visit(const SymLinkMapping& linkObj)
- {
- switch (colType_)
- {
- case xmlAccess::FULL_PATH:
- value = toWx(linkObj.getFullName<side>().BeforeLast(FILE_NAME_SEPARATOR));
- break;
- case xmlAccess::FILENAME: //filename
- value = toWx(linkObj.getShortName<side>());
- break;
- case xmlAccess::REL_PATH: //relative path
- value = toWx(linkObj.getObjRelativeName().BeforeLast(FILE_NAME_SEPARATOR)); //returns empty string if ch not found
- break;
- case xmlAccess::DIRECTORY:
- value = toWx(linkObj.getBaseDirPf<side>());
- break;
- case xmlAccess::SIZE: //file size
- if (!fsObj_.isEmpty<side>())
- value = _("<Symlink>");
- break;
- case xmlAccess::DATE: //date
- if (!fsObj_.isEmpty<side>())
- value = zen::utcTimeToLocalString(linkObj.getLastWriteTime<side>());
- break;
- case xmlAccess::EXTENSION: //file extension
- value = wxEmptyString;
- break;
- }
- }
-
- virtual void visit(const DirMapping& dirObj)
- {
- switch (colType_)
- {
- case xmlAccess::FULL_PATH:
- value = toWx(dirObj.getFullName<side>());
- break;
- case xmlAccess::FILENAME:
- value = toWx(dirObj.getShortName<side>());
- break;
- case xmlAccess::REL_PATH:
- value = toWx(dirObj.getObjRelativeName().BeforeLast(FILE_NAME_SEPARATOR)); //returns empty string if ch not found
- break;
- case xmlAccess::DIRECTORY:
- value = toWx(dirObj.getBaseDirPf<side>());
- break;
- case xmlAccess::SIZE: //file size
- if (!fsObj_.isEmpty<side>())
- value = _("<Directory>");
- break;
- case xmlAccess::DATE: //date
- if (!fsObj_.isEmpty<side>())
- value = wxEmptyString;
- break;
- case xmlAccess::EXTENSION: //file extension
- value = wxEmptyString;
- break;
- }
- }
- xmlAccess::ColumnTypes colType_;
- wxString value;
-
- const FileSystemObject& fsObj_;
- } getVal(getTypeAtPos(col), *fsObj);
- fsObj->accept(getVal);
- return getVal.value;
- }
- //if data is not found:
- return wxEmptyString;
- }
-
- template <SelectedSide side>
- Zstring getIconFileImpl(size_t row) const //return "folder" if row points to a folder
- {
- const FileSystemObject* fsObj = getRawData(row);
- if (fsObj && !fsObj->isEmpty<side>())
- {
- struct GetIcon : public FSObjectVisitor
- {
- virtual void visit(const FileMapping& fileObj)
- {
- //Optimization: if filename exists on both sides, always use left side's file
- //if (!fileObj.isEmpty<LEFT_SIDE>() && !fileObj.isEmpty<RIGHT_SIDE>())
- // iconName = fileObj.getFullName<LEFT_SIDE>();
- //else -> now with thumbnails this isn't viable anymore
- iconName = fileObj.getFullName<side>();
- }
- virtual void visit(const SymLinkMapping& linkObj)
- {
- iconName = linkObj.getLinkType<side>() == LinkDescriptor::TYPE_DIR ?
- Zstr("folder") :
- linkObj.getFullName<side>();
- }
- virtual void visit(const DirMapping& dirObj)
- {
- iconName = Zstr("folder");
- }
-
- Zstring iconName;
- } getIcon;
- fsObj->accept(getIcon);
- return getIcon.iconName;
- }
-
- return Zstring();
- }
-
-
-private:
- virtual const std::pair<wxColour, wxColour> getRowColor(int row) //rows that are filtered out are shown in different color: <foreground, background>
- {
- std::pair<wxColour, wxColour> result(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT),
- wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
-
- const FileSystemObject* fsObj = getRawData(row);
- if (fsObj)
- {
- //mark filtered rows
- if (!fsObj->isActive())
- {
- result.first = *wxBLACK;
- result.second = COLOR_BLUE;
- }
- else
- {
- //mark directories and symlinks
- struct GetRowColor : public FSObjectVisitor
- {
- GetRowColor(wxColour& foreground, wxColour& background) : foreground_(foreground), background_(background) {}
-
- virtual void visit(const FileMapping& fileObj) {}
- virtual void visit(const SymLinkMapping& linkObj)
- {
- foreground_ = *wxBLACK;
- background_ = COLOR_ORANGE;
- }
- virtual void visit(const DirMapping& dirObj)
- {
- foreground_ = *wxBLACK;
- background_ = COLOR_GREY;
- }
-
- private:
- wxColour& foreground_;
- wxColour& background_;
- } getCol(result.first, result.second);
- fsObj->accept(getCol);
- }
- }
-
- return result;
- }
-
- std::vector<xmlAccess::ColumnTypes> columnPositions;
-};
-
-
-class CustomGridTableLeft : public CustomGridTableRim
-{
-public:
-
- virtual wxString GetValue(int row, int col)
- {
- return CustomGridTableRim::GetValueSub<LEFT_SIDE>(row, col);
- }
-
- virtual Zstring getIconFile(size_t row) const //return "folder" if row points to a folder
- {
- return getIconFileImpl<LEFT_SIDE>(row);
- }
-};
-
-
-class CustomGridTableRight : public CustomGridTableRim
-{
-public:
- virtual wxString GetValue(int row, int col)
- {
- return CustomGridTableRim::GetValueSub<RIGHT_SIDE>(row, col);
- }
-
- virtual Zstring getIconFile(size_t row) const //return "folder" if row points to a folder
- {
- return getIconFileImpl<RIGHT_SIDE>(row);
- }
-};
-
-
-class CustomGridTableMiddle : public CustomGridTable
-{
-public:
- //middle grid is created (first wxWidgets internal call to GetNumberCols()) with one column
- CustomGridTableMiddle() :
- CustomGridTable(0, GetNumberCols()), //attention: static binding to virtual GetNumberCols() in a Constructor!
- syncPreviewActive(false) {}
-
- virtual int GetNumberCols()
- {
- return 1;
- }
-
- virtual wxString GetColLabelValue( int col )
- {
- return wxEmptyString;
- }
-
- virtual wxString GetValue(int row, int col) //method used for exporting .csv file only!
- {
- const FileSystemObject* fsObj = getRawData(row);
- if (fsObj)
- {
- if (syncPreviewActive) //synchronization preview
- return getSymbol(fsObj->getSyncOperation());
- else
- return getSymbol(fsObj->getCategory());
- }
- return wxEmptyString;
- }
-
- void enableSyncPreview(bool value)
- {
- syncPreviewActive = value;
- }
-
- bool syncPreviewIsActive() const
- {
- return syncPreviewActive;
- }
-
-private:
- virtual const std::pair<wxColour, wxColour> getRowColor(int row) //rows that are filtered out are shown in different color: <foreground, background>
- {
- std::pair<wxColour, wxColour> result(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT),
- wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
-
- const FileSystemObject* fsObj = getRawData(row);
- if (fsObj)
- {
- //mark filtered rows
- if (!fsObj->isActive())
- {
- result.first = *wxBLACK;;
- result.second = COLOR_BLUE;
- }
- else
- {
- if (syncPreviewActive) //synchronization preview
- {
- switch (fsObj->getSyncOperation()) //evaluate comparison result and sync direction
- {
- case SO_DO_NOTHING:
- case SO_EQUAL:
- break;//usually white
- case SO_CREATE_NEW_LEFT:
- case SO_OVERWRITE_LEFT:
- case SO_DELETE_LEFT:
- result.first = *wxBLACK;
- result.second = COLOR_SYNC_BLUE;
- break;
- case SO_COPY_METADATA_TO_LEFT:
- result.first = *wxBLACK;
- result.second = COLOR_SYNC_BLUE_LIGHT;
- break;
- case SO_CREATE_NEW_RIGHT:
- case SO_OVERWRITE_RIGHT:
- case SO_DELETE_RIGHT:
- result.first = *wxBLACK;
- result.second = COLOR_SYNC_GREEN;
- break;
- case SO_COPY_METADATA_TO_RIGHT:
- result.first = *wxBLACK;
- result.second = COLOR_SYNC_GREEN_LIGHT;
- break;
- case SO_UNRESOLVED_CONFLICT:
- result.first = *wxBLACK;
- result.second = COLOR_YELLOW;
- break;
- }
- }
- else //comparison results view
- {
- switch (fsObj->getCategory())
- {
- case FILE_LEFT_SIDE_ONLY:
- case FILE_LEFT_NEWER:
- result.first = *wxBLACK;
- result.second = COLOR_SYNC_BLUE; //COLOR_CMP_BLUE;
- break;
-
- case FILE_RIGHT_SIDE_ONLY:
- case FILE_RIGHT_NEWER:
- result.first = *wxBLACK;
- result.second = COLOR_SYNC_GREEN; //COLOR_CMP_GREEN;
- break;
- case FILE_DIFFERENT:
- result.first = *wxBLACK;
- result.second = COLOR_CMP_RED;
- break;
- case FILE_EQUAL:
- break;//usually white
- case FILE_CONFLICT:
- result.first = *wxBLACK;
- result.second = COLOR_YELLOW;
- break;
- case FILE_DIFFERENT_METADATA:
- result.first = *wxBLACK;
- result.second = COLOR_YELLOW_LIGHT;
- break;
- }
- }
- }
- }
-
- return result;
- }
-
- bool syncPreviewActive; //determines wheter grid shall show compare result or sync preview
-};
-
-//########################################################################################################
-
-
-CustomGrid::CustomGrid(wxWindow* parent,
- wxWindowID id,
- const wxPoint& pos,
- const wxSize& size,
- long style,
- const wxString& name) :
- wxGrid(parent, id, pos, size, style, name),
- m_gridLeft(NULL),
- m_gridMiddle(NULL),
- m_gridRight(NULL),
- isLeading(false),
- m_marker(-1, ASCENDING)
-{
- //wxColour darkBlue(40, 35, 140); -> user default colors instead!
- //SetSelectionBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
- //SetSelectionForeground(*wxWHITE);
-}
-
-
-void CustomGrid::initSettings(CustomGridLeft* gridLeft,
- CustomGridMiddle* gridMiddle,
- CustomGridRight* gridRight,
- const GridView* gridDataView)
-{
- assert(this == gridLeft || this == gridRight || this == gridMiddle);
-
- //these grids will scroll together
- m_gridLeft = gridLeft;
- m_gridRight = gridRight;
- m_gridMiddle = gridMiddle;
-
- //enhance grid functionality; identify leading grid by keyboard input or scroll action
- Connect(wxEVT_KEY_DOWN, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_TOP, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_BOTTOM, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_LINEUP, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_LINEDOWN, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_PAGEUP, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_PAGEDOWN, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_THUMBTRACK, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SCROLLWIN_THUMBRELEASE, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_GRID_LABEL_LEFT_CLICK, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- Connect(wxEVT_SET_FOCUS, wxEventHandler(CustomGrid::onGridAccess), NULL, this); //used by grid text-search
- GetGridWindow()->Connect(wxEVT_LEFT_DOWN, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
- GetGridWindow()->Connect(wxEVT_RIGHT_DOWN, wxEventHandler(CustomGrid::onGridAccess), NULL, this);
-
- GetGridWindow()->Connect(wxEVT_ENTER_WINDOW, wxEventHandler(CustomGrid::adjustGridHeights), NULL, this);
-
- //parallel grid scrolling: do NOT use DoPrepareDC() to align grids! GDI resource leak! Use regular paint event instead:
- GetGridWindow()->Connect(wxEVT_PAINT, wxEventHandler(CustomGrid::OnPaintGrid), NULL, this);
-}
-
-
-void CustomGrid::release() //release connection to zen::GridView
-{
- assert(getGridDataTable());
- getGridDataTable()->setGridDataTable(NULL); //kind of "disable" griddatatable; don't delete it with SetTable(NULL)! May be used by wxGridCellStringRenderer
-}
-
-
-bool CustomGrid::isLeadGrid() const
-{
- return isLeading;
-}
-
-
-void CustomGrid::setIconManager(const std::shared_ptr<IconBuffer>& iconBuffer)
-{
- if (iconBuffer.get())
- SetDefaultRowSize(iconBuffer->getSize() + 1, true); //+ 1 for line between rows
- else
- SetDefaultRowSize(IconBuffer(IconBuffer::SIZE_SMALL).getSize() + 1, true); //currently iconBuffer is always bound, but we may use it as a "no icon" status at some time...
-
- enableFileIcons(iconBuffer);
- Refresh();
-}
-
-
-void CustomGrid::RefreshCell(int row, int col)
-{
- wxRect rectScrolled(CellToRect(row, col));
- //use: wxRect rect = CellToRect( row, col ); ?
- CalcScrolledPosition(rectScrolled.x, rectScrolled.y, &rectScrolled.x, &rectScrolled.y);
-
- GetGridWindow()->RefreshRect(rectScrolled); //note: CellToRect() and YToRow work on m_gridWindow NOT on the whole grid!
-}
-
-
-void CustomGrid::OnPaintGrid(wxEvent& event)
-{
- if (isLeadGrid()) //avoid back coupling
- alignOtherGrids(m_gridLeft, m_gridMiddle, m_gridRight); //scroll other grids
- event.Skip();
-}
-
-
-void moveCursorWhileSelecting(int anchor, int oldPos, int newPos, wxGrid* grid)
-{
- //note: all positions are valid in this context!
-
- grid->SetGridCursor( newPos, grid->GetGridCursorCol());
- grid->MakeCellVisible(newPos, grid->GetGridCursorCol());
-
- if (oldPos < newPos)
- {
- for (int i = oldPos; i < std::min(anchor, newPos); ++i)
- grid->DeselectRow(i); //remove selection
-
- for (int i = std::max(oldPos, anchor); i <= newPos; ++i)
- grid->SelectRow(i, true); //add to selection
- }
- else
- {
- for (int i = std::max(newPos, anchor) + 1; i <= oldPos; ++i)
- grid->DeselectRow(i); //remove selection
-
- for (int i = newPos; i <= std::min(oldPos, anchor); ++i)
- grid->SelectRow(i, true); //add to selection
- }
-}
-
-
-void execGridCommands(wxEvent& event, wxGrid* grid)
-{
- static int anchorRow = 0;
- if (grid->GetNumberRows() == 0 ||
- grid->GetNumberCols() == 0)
- return;
-
- const wxKeyEvent* keyEvent = dynamic_cast<const wxKeyEvent*> (&event);
- if (keyEvent)
- {
- //ensure cursorOldPos is always a valid row!
- const int cursorOldPos = std::max(std::min(grid->GetGridCursorRow(), grid->GetNumberRows() - 1), 0);
- const int cursorOldColumn = std::max(std::min(grid->GetGridCursorCol(), grid->GetNumberCols() - 1), 0);
-
- const bool shiftPressed = keyEvent->ShiftDown();
- const bool ctrlPressed = keyEvent->ControlDown();
- const int keyCode = keyEvent->GetKeyCode();
-
- //SHIFT + X
- if (shiftPressed)
- switch (keyCode)
- {
- case WXK_UP:
- case WXK_NUMPAD_UP:
- {
- const int cursorNewPos = std::max(cursorOldPos - 1, 0);
- moveCursorWhileSelecting(anchorRow, cursorOldPos, cursorNewPos, grid);
- return; //no event.Skip()
- }
- case WXK_DOWN:
- case WXK_NUMPAD_DOWN:
- {
- const int cursorNewPos = std::min(cursorOldPos + 1, grid->GetNumberRows() - 1);
- moveCursorWhileSelecting(anchorRow, cursorOldPos, cursorNewPos, grid);
- return; //no event.Skip()
- }
- case WXK_LEFT:
- case WXK_NUMPAD_LEFT:
- {
- const int cursorColumn = std::max(cursorOldColumn - 1, 0);
- grid->SetGridCursor(cursorOldPos, cursorColumn);
- grid->MakeCellVisible(cursorOldPos, cursorColumn);
- return; //no event.Skip()
- }
- case WXK_RIGHT:
- case WXK_NUMPAD_RIGHT:
- {
- const int cursorColumn = std::min(cursorOldColumn + 1, grid->GetNumberCols() - 1);
- grid->SetGridCursor(cursorOldPos, cursorColumn);
- grid->MakeCellVisible(cursorOldPos, cursorColumn);
- return; //no event.Skip()
- }
- case WXK_PAGEUP:
- case WXK_NUMPAD_PAGEUP:
- {
- const int rowsPerPage = grid->GetGridWindow()->GetSize().GetHeight() / grid->GetDefaultRowSize();
- const int cursorNewPos = std::max(cursorOldPos - rowsPerPage, 0);
- moveCursorWhileSelecting(anchorRow, cursorOldPos, cursorNewPos, grid);
- return; //no event.Skip()
- }
- case WXK_PAGEDOWN:
- case WXK_NUMPAD_PAGEDOWN:
- {
- const int rowsPerPage = grid->GetGridWindow()->GetSize().GetHeight() / grid->GetDefaultRowSize();
- const int cursorNewPos = std::min(cursorOldPos + rowsPerPage, grid->GetNumberRows() - 1);
- moveCursorWhileSelecting(anchorRow, cursorOldPos, cursorNewPos, grid);
- return; //no event.Skip()
- }
- case WXK_HOME:
- case WXK_NUMPAD_HOME:
- {
- const int cursorNewPos = 0;
- moveCursorWhileSelecting(anchorRow, cursorOldPos, cursorNewPos, grid);
- return; //no event.Skip()
- }
- case WXK_END:
- case WXK_NUMPAD_END:
- {
- const int cursorNewPos = grid->GetNumberRows() - 1;
- moveCursorWhileSelecting(anchorRow, cursorOldPos, cursorNewPos, grid);
- return; //no event.Skip()
- }
- }
-
- //CTRL + X
- if (ctrlPressed)
- switch (keyCode)
- {
- case WXK_UP:
- case WXK_NUMPAD_UP:
- {
- grid->SetGridCursor(0, grid->GetGridCursorCol());
- grid->MakeCellVisible(0, grid->GetGridCursorCol());
- return; //no event.Skip()
- }
- case WXK_DOWN:
- case WXK_NUMPAD_DOWN:
- {
- grid->SetGridCursor(grid->GetNumberRows() - 1, grid->GetGridCursorCol());
- grid->MakeCellVisible(grid->GetNumberRows() - 1, grid->GetGridCursorCol());
- return; //no event.Skip()
- }
- case WXK_LEFT:
- case WXK_NUMPAD_LEFT:
- {
- grid->SetGridCursor(grid->GetGridCursorRow(), 0);
- grid->MakeCellVisible(grid->GetGridCursorRow(), 0);
- return; //no event.Skip()
- }
- case WXK_RIGHT:
- case WXK_NUMPAD_RIGHT:
- {
- grid->SetGridCursor(grid->GetGridCursorRow(), grid->GetNumberCols() - 1);
- grid->MakeCellVisible(grid->GetGridCursorRow(), grid->GetNumberCols() - 1);
- return; //no event.Skip()
- }
- }
-
- //button with or without control keys pressed
- switch (keyCode)
- {
- case WXK_HOME:
- case WXK_NUMPAD_HOME:
- {
- grid->SetGridCursor(0, grid->GetGridCursorCol());
- grid->MakeCellVisible(0, grid->GetGridCursorCol());
- return; //no event.Skip()
- }
- case WXK_END:
- case WXK_NUMPAD_END:
- {
- grid->SetGridCursor(grid->GetNumberRows() - 1, grid->GetGridCursorCol());
- grid->MakeCellVisible(grid->GetNumberRows() - 1, grid->GetGridCursorCol());
- return; //no event.Skip()
- }
-
- case WXK_PAGEUP:
- case WXK_NUMPAD_PAGEUP:
- {
- const int rowsPerPage = grid->GetGridWindow()->GetSize().GetHeight() / grid->GetDefaultRowSize();
- const int cursorNewPos = std::max(cursorOldPos - rowsPerPage, 0);
- grid->SetGridCursor(cursorNewPos, grid->GetGridCursorCol());
- grid->MakeCellVisible(cursorNewPos, grid->GetGridCursorCol());
- return; //no event.Skip()
- }
- case WXK_PAGEDOWN:
- case WXK_NUMPAD_PAGEDOWN:
- {
- const int rowsPerPage = grid->GetGridWindow()->GetSize().GetHeight() / grid->GetDefaultRowSize();
- const int cursorNewPos = std::min(cursorOldPos + rowsPerPage, grid->GetNumberRows() - 1);
- grid->SetGridCursor(cursorNewPos, grid->GetGridCursorCol());
- grid->MakeCellVisible(cursorNewPos, grid->GetGridCursorCol());
- return; //no event.Skip()
- }
- }
-
- //button without additonal control keys pressed
- if (keyEvent->GetModifiers() == wxMOD_NONE)
- switch (keyCode)
- {
- case WXK_UP:
- case WXK_NUMPAD_UP:
- {
- const int cursorNewPos = std::max(cursorOldPos - 1, 0);
- grid->SetGridCursor(cursorNewPos, grid->GetGridCursorCol());
- grid->MakeCellVisible(cursorNewPos, grid->GetGridCursorCol());
- return; //no event.Skip()
- }
- case WXK_DOWN:
- case WXK_NUMPAD_DOWN:
- {
- const int cursorNewPos = std::min(cursorOldPos + 1, grid->GetNumberRows() - 1);
- grid->SetGridCursor(cursorNewPos, grid->GetGridCursorCol());
- grid->MakeCellVisible(cursorNewPos, grid->GetGridCursorCol());
- return; //no event.Skip()
- }
- case WXK_LEFT:
- case WXK_NUMPAD_LEFT:
- {
- const int cursorColumn = std::max(cursorOldColumn - 1, 0);
- grid->SetGridCursor(cursorOldPos, cursorColumn);
- grid->MakeCellVisible(cursorOldPos, cursorColumn);
- return; //no event.Skip()
- }
- case WXK_RIGHT:
- case WXK_NUMPAD_RIGHT:
- {
- const int cursorColumn = std::min(cursorOldColumn + 1, grid->GetNumberCols() - 1);
- grid->SetGridCursor(cursorOldPos, cursorColumn);
- grid->MakeCellVisible(cursorOldPos, cursorColumn);
- return; //no event.Skip()
- }
- }
- }
-
- anchorRow = grid->GetGridCursorRow();
- event.Skip(); //let event delegate!
-}
-
-
-inline
-bool gridsShouldBeCleared(const wxEvent& event)
-{
- const wxMouseEvent* mouseEvent = dynamic_cast<const wxMouseEvent*>(&event);
- if (mouseEvent)
- {
- if (mouseEvent->ControlDown() || mouseEvent->ShiftDown())
- return false;
-
- if (mouseEvent->ButtonDown(wxMOUSE_BTN_LEFT))
- return true;
- }
- else
- {
- const wxKeyEvent* keyEvent = dynamic_cast<const wxKeyEvent*>(&event);
- if (keyEvent)
- {
- if (keyEvent->ControlDown() || keyEvent->AltDown() || keyEvent->ShiftDown())
- return false;
-
- switch (keyEvent->GetKeyCode())
- {
- //default navigation keys
- case WXK_UP:
- case WXK_DOWN:
- case WXK_LEFT:
- case WXK_RIGHT:
- case WXK_PAGEUP:
- case WXK_PAGEDOWN:
- case WXK_HOME:
- case WXK_END:
- case WXK_NUMPAD_UP:
- case WXK_NUMPAD_DOWN:
- case WXK_NUMPAD_LEFT:
- case WXK_NUMPAD_RIGHT:
- case WXK_NUMPAD_PAGEUP:
- case WXK_NUMPAD_PAGEDOWN:
- case WXK_NUMPAD_HOME:
- case WXK_NUMPAD_END:
- //other keys
- case WXK_TAB:
- case WXK_RETURN:
- case WXK_NUMPAD_ENTER:
- case WXK_ESCAPE:
- return true;
- }
- }
- }
-
- return false;
-}
-
-
-void CustomGrid::onGridAccess(wxEvent& event)
-{
- if (!isLeading)
- {
- //notify other grids of new user focus
- m_gridLeft ->isLeading = m_gridLeft == this;
- m_gridMiddle->isLeading = m_gridMiddle == this;
- m_gridRight ->isLeading = m_gridRight == this;
-
- wxGrid::SetFocus();
- }
-
- //clear grids
- if (gridsShouldBeCleared(event))
- {
- m_gridLeft ->ClearSelection();
- m_gridMiddle->ClearSelection();
- m_gridRight ->ClearSelection();
- }
-
- //update row labels NOW (needed when scrolling if buttons keep being pressed)
- m_gridLeft ->GetGridRowLabelWindow()->Update();
- m_gridRight->GetGridRowLabelWindow()->Update();
-
- //support for custom short-cuts (overwriting wxWidgets functionality!)
- execGridCommands(event, this); //event.Skip is handled here!
-}
-
-
-//workaround: ensure that all grids are properly aligned: add some extra window space to grids that have no horizontal scrollbar
-void CustomGrid::adjustGridHeights(wxEvent& event)
-{
- //m_gridLeft, m_gridRight, m_gridMiddle not NULL because called after initSettings()
-
- int y1 = 0;
- int y2 = 0;
- int y3 = 0;
- int dummy = 0;
-
- m_gridLeft ->GetViewStart(&dummy, &y1);
- m_gridRight ->GetViewStart(&dummy, &y2);
- m_gridMiddle->GetViewStart(&dummy, &y3);
-
- if (y1 != y2 || y2 != y3)
- {
- int yMax = std::max(y1, std::max(y2, y3));
-
- if (m_gridLeft->isLeadGrid()) //do not handle case (y1 == yMax) here!!! Avoid back coupling!
- m_gridLeft->SetMargins(0, 0);
- else if (y1 < yMax)
- m_gridLeft->SetMargins(0, 30);
-
- if (m_gridRight->isLeadGrid())
- m_gridRight->SetMargins(0, 0);
- else if (y2 < yMax)
- m_gridRight->SetMargins(0, 30);
-
- if (m_gridMiddle->isLeadGrid())
- m_gridMiddle->SetMargins(0, 0);
- else if (y3 < yMax)
- m_gridMiddle->SetMargins(0, 30);
-
- m_gridLeft ->ForceRefresh();
- m_gridRight ->ForceRefresh();
- m_gridMiddle->ForceRefresh();
- }
-}
-
-
-void CustomGrid::updateGridSizes()
-{
- if (getGridDataTable())
- getGridDataTable()->updateGridSizes();
-}
-
-
-void CustomGridRim::updateGridSizes()
-{
- CustomGrid::updateGridSizes();
-
- //set row label size
-
- //SetRowLabelSize(wxGRID_AUTOSIZE); -> we can do better
- wxClientDC dc(GetGridRowLabelWindow());
- dc.SetFont(GetLabelFont());
-
- wxArrayString lines;
- lines.push_back(GetRowLabelValue(GetNumberRows()));
-
- long width = 0;
- long dummy = 0;
- GetTextBoxSize(dc, lines, &width, &dummy);
-
- width += 8;
- SetRowLabelSize(width);
-}
-
-
-void CustomGrid::setSortMarker(SortMarker marker)
-{
- m_marker = marker;
-}
-
-
-void CustomGrid::DrawColLabel(wxDC& dc, int col)
-{
- wxGrid::DrawColLabel(dc, col);
-
- if (col == m_marker.first)
- {
- if (m_marker.second == ASCENDING)
- dc.DrawBitmap(GlobalResources::getImage(wxT("smallUp")), GetColRight(col) - 16 - 2, 2, true); //respect 2-pixel border
- else
- dc.DrawBitmap(GlobalResources::getImage(wxT("smallDown")), GetColRight(col) - 16 - 2, 2, true); //respect 2-pixel border
- }
-}
-
-
-std::pair<int, int> CustomGrid::mousePosToCell(wxPoint pos)
-{
- int x = -1;
- int y = -1;
- CalcUnscrolledPosition(pos.x, pos.y, &x, &y);
-
- std::pair<int, int> output(-1, -1);
- if (x >= 0 && y >= 0)
- {
- output.first = YToRow(y);
- output.second = XToCol(x);
- }
- return output;
-}
-
-
-std::set<size_t> CustomGrid::getAllSelectedRows() const
-{
- std::set<size_t> output;
-
- const wxArrayInt selectedRows = this->GetSelectedRows();
- if (!selectedRows.IsEmpty())
- {
- for (size_t i = 0; i < selectedRows.GetCount(); ++i)
- output.insert(selectedRows[i]);
- }
-
- if (!this->GetSelectedCols().IsEmpty()) //if a column is selected this is means all rows are marked for deletion
- {
- for (int k = 0; k < const_cast<CustomGrid*>(this)->GetNumberRows(); ++k) //messy wxGrid implementation...
- output.insert(k);
- }
-
- const wxGridCellCoordsArray singlySelected = this->GetSelectedCells();
- if (!singlySelected.IsEmpty())
- {
- for (size_t k = 0; k < singlySelected.GetCount(); ++k)
- output.insert(singlySelected[k].GetRow());
- }
-
- const wxGridCellCoordsArray tmpArrayTop = this->GetSelectionBlockTopLeft();
- if (!tmpArrayTop.IsEmpty())
- {
- wxGridCellCoordsArray tmpArrayBottom = this->GetSelectionBlockBottomRight();
-
- size_t arrayCount = tmpArrayTop.GetCount();
-
- if (arrayCount == tmpArrayBottom.GetCount())
- {
- for (size_t i = 0; i < arrayCount; ++i)
- {
- const int rowTop = tmpArrayTop[i].GetRow();
- const int rowBottom = tmpArrayBottom[i].GetRow();
-
- for (int k = rowTop; k <= rowBottom; ++k)
- output.insert(k);
- }
- }
- }
-
- //some exception: also add current cursor row to selection if there are no others... hopefully improving usability
- if (output.empty() && this->isLeadGrid())
- output.insert(const_cast<CustomGrid*>(this)->GetCursorRow()); //messy wxGrid implementation...
-
- return output;
-}
-
-
-//############################################################################################
-//CustomGrid specializations
-
-class GridCellRenderer : public wxGridCellStringRenderer
-{
-public:
- GridCellRenderer(CustomGridRim::FailedIconLoad& failedLoads,
- const CustomGridTableRim* gridDataTable,
- const std::shared_ptr<zen::IconBuffer>& iconBuffer) :
- failedLoads_(failedLoads),
- m_gridDataTable(gridDataTable),
- iconBuffer_(iconBuffer) {}
-
-
- virtual void Draw(wxGrid& grid,
- wxGridCellAttr& attr,
- wxDC& dc,
- const wxRect& rect, //unscrolled rect
- int row, int col,
- bool isSelected)
- {
- //############## show windows explorer file icons ######################
-
- if (iconBuffer_.get() &&
- m_gridDataTable->getTypeAtPos(col) == xmlAccess::FILENAME)
- {
- const int iconSize = iconBuffer_->getSize();
- if (rect.GetWidth() >= iconSize)
- {
- // Partitioning:
- // ____________________________
- // | 2 pix border | icon | rest |
- // ----------------------------
- {
- //clear area where icon will be placed (including border)
- wxRect rectShrinked(rect);
- rectShrinked.SetWidth(LEFT_BORDER + iconSize); //add 2 pixel border
- wxGridCellRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected);
- }
-
- {
- //draw rest
- wxRect rest(rect); //unscrolled
- rest.x += LEFT_BORDER + iconSize;
- rest.width -= LEFT_BORDER + iconSize;
- wxGridCellStringRenderer::Draw(grid, attr, dc, rest, row, col, isSelected);
- }
-
- wxRect rectIcon(rect);
- rectIcon.SetWidth(iconSize); //set to icon area only
- rectIcon.x += LEFT_BORDER; //
-
- //try to draw icon
- //retrieve grid data
- const Zstring fileName = m_gridDataTable->getIconFile(row);
- if (!fileName.empty())
- {
- wxIcon icon;
-
- //first check if it is a directory icon:
- if (fileName == Zstr("folder"))
- icon = iconBuffer_->genericDirIcon();
- else //retrieve file icon
- {
- if (!iconBuffer_->requestFileIcon(fileName, &icon)) //returns false if icon is not in buffer
- {
- icon = iconBuffer_->genericFileIcon(); //better than nothing
-
- failedLoads_.insert(row); //save status of failed icon load -> used for async. icon loading
- //falsify only! we want to avoid writing incorrect success values when only partially updating the DC, e.g. when scrolling,
- //see repaint behavior of ::ScrollWindow() function!
- }
- }
-
- if (icon.IsOk())
- {
- int posX = rectIcon.GetX();
- int posY = rectIcon.GetY();
- //center icon if it is too small
- if (rectIcon.GetWidth() > icon.GetWidth())
- posX += (rectIcon.GetWidth() - icon.GetWidth()) / 2;
- if (rectIcon.GetHeight() > icon.GetHeight())
- posY += (rectIcon.GetHeight() - icon.GetHeight()) / 2;
-
- dc.DrawIcon(icon, posX, posY);
- }
- }
- 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 (iconBuffer_.get() && //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_->getSize());
- return rv;
- }
-
- //default
- return wxGridCellStringRenderer::GetBestSize(grid, attr, dc, row, col);
- }
-
-
-private:
- CustomGridRim::FailedIconLoad& failedLoads_;
- const CustomGridTableRim* const m_gridDataTable;
- std::shared_ptr<zen::IconBuffer> iconBuffer_;
-
- static const int LEFT_BORDER = 2;
-};
-
-//----------------------------------------------------------------------------------------
-
-CustomGridRim::CustomGridRim(wxWindow* parent,
- wxWindowID id,
- const wxPoint& pos,
- const wxSize& size,
- long style,
- const wxString& name) :
- CustomGrid(parent, id, pos, size, style, name), otherGrid(NULL)
-{
- Connect(wxEVT_GRID_COL_SIZE, wxGridSizeEventHandler(CustomGridRim::OnResizeColumn), NULL, this); //row-based tooltip
-}
-
-
-void CustomGridRim::setOtherGrid(CustomGridRim* other) //call during initialization!
-{
- otherGrid = other;
-}
-
-
-void CustomGridRim::OnResizeColumn(wxGridSizeEvent& event)
-{
- //Resize columns on both sides in parallel
- const int thisCol = event.GetRowOrCol();
-
- if (!otherGrid || thisCol < 0 || thisCol >= GetNumberCols()) return;
-
- const xmlAccess::ColumnTypes thisColType = getTypeAtPos(thisCol);
-
- for (int i = 0; i < otherGrid->GetNumberCols(); ++i)
- if (otherGrid->getTypeAtPos(i) == thisColType)
- {
- otherGrid->SetColSize(i, GetColSize(thisCol));
- otherGrid->ForceRefresh();
- break;
- }
-}
-
-
-//this method is called when grid view changes: useful for parallel updating of multiple grids
-void CustomGridRim::alignOtherGrids(CustomGrid* gridLeft, CustomGrid* gridMiddle, CustomGrid* gridRight)
-{
- if (!otherGrid) return;
-
- int x = 0;
- int y = 0;
- GetViewStart(&x, &y);
- gridMiddle->Scroll(-1, y);
- otherGrid->Scroll(x, y);
-}
-
-
-template <SelectedSide side>
-void CustomGridRim::setTooltip(const wxMouseEvent& event)
-{
- const int hoveredRow = mousePosToCell(event.GetPosition()).first;
-
- wxString toolTip;
- if (hoveredRow >= 0 && getGridDataTable() != NULL)
- {
- const FileSystemObject* const fsObj = getGridDataTable()->getRawData(hoveredRow);
- if (fsObj && !fsObj->isEmpty<side>())
- {
- struct AssembleTooltip : public FSObjectVisitor
- {
- AssembleTooltip(wxString& tipMsg) : tipMsg_(tipMsg) {}
-
- virtual void visit(const FileMapping& fileObj)
- {
- tipMsg_ = toWx(fileObj.getRelativeName<side>()) + "\n" +
- _("Size") + ": " + zen::formatFilesizeToShortString(fileObj.getFileSize<side>()) + "\n" +
- _("Date") + ": " + zen::utcTimeToLocalString(fileObj.getLastWriteTime<side>());
- }
-
- virtual void visit(const SymLinkMapping& linkObj)
- {
- tipMsg_ = toWx(linkObj.getRelativeName<side>()) + "\n" +
- _("Date") + ": " + zen::utcTimeToLocalString(linkObj.getLastWriteTime<side>());
- }
-
- virtual void visit(const DirMapping& dirObj)
- {
- tipMsg_ = toWx(dirObj.getRelativeName<side>());
- }
-
- wxString& tipMsg_;
- } assembler(toolTip);
- fsObj->accept(assembler);
- }
- }
-
-
- wxToolTip* tt = GetGridWindow()->GetToolTip();
-
- const wxString currentTip = tt ? tt->GetTip() : wxString();
- if (toolTip != currentTip)
- {
- if (toolTip.IsEmpty())
- GetGridWindow()->SetToolTip(NULL); //wxGTK doesn't allow wxToolTip with empty text!
- else
- {
- //wxWidgets bug: tooltip multiline property is defined by first tooltip text containing newlines or not (same is true for maximum width)
- if (!tt)
- GetGridWindow()->SetToolTip(new wxToolTip(wxT("a b\n\
- a b"))); //ugly, but is working (on Windows)
- tt = GetGridWindow()->GetToolTip(); //should be bound by now
- if (tt)
- tt->SetTip(toolTip);
- }
- }
-}
-
-
-xmlAccess::ColumnAttributes CustomGridRim::getDefaultColumnAttributes()
-{
- xmlAccess::ColumnAttributes defaultColumnSettings;
-
- xmlAccess::ColumnAttrib newEntry;
- newEntry.type = xmlAccess::FULL_PATH;
- newEntry.visible = false;
- newEntry.position = 0;
- newEntry.width = 150;
- defaultColumnSettings.push_back(newEntry);
-
- newEntry.type = xmlAccess::DIRECTORY;
- newEntry.position = 1;
- newEntry.width = 140;
- defaultColumnSettings.push_back(newEntry);
-
- newEntry.type = xmlAccess::REL_PATH;
- newEntry.visible = true;
- newEntry.position = 2;
- newEntry.width = 118;
- defaultColumnSettings.push_back(newEntry);
-
- newEntry.type = xmlAccess::FILENAME;
- newEntry.position = 3;
- newEntry.width = 138;
- defaultColumnSettings.push_back(newEntry);
-
- newEntry.type = xmlAccess::SIZE;
- newEntry.position = 4;
- newEntry.width = 70;
- defaultColumnSettings.push_back(newEntry);
-
- newEntry.type = xmlAccess::DATE;
- newEntry.position = 5;
- newEntry.width = 113;
- defaultColumnSettings.push_back(newEntry);
-
- newEntry.type = xmlAccess::EXTENSION;
- newEntry.visible = false;
- newEntry.position = 6;
- newEntry.width = 60;
- defaultColumnSettings.push_back(newEntry);
-
- return defaultColumnSettings;
-}
-
-
-xmlAccess::ColumnAttributes CustomGridRim::getColumnAttributes()
-{
- std::sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByPositionAndVisibility);
-
- xmlAccess::ColumnAttributes output;
- xmlAccess::ColumnAttrib newEntry;
- for (size_t i = 0; i < columnSettings.size(); ++i)
- {
- newEntry = columnSettings[i];
- if (newEntry.visible)
- newEntry.width = GetColSize(static_cast<int>(i)); //hidden columns are sorted to the end of vector!
- output.push_back(newEntry);
- }
-
- return output;
-}
-
-
-void CustomGridRim::setColumnAttributes(const xmlAccess::ColumnAttributes& attr)
-{
- //remove special alignment for column "size"
- if (GetLayoutDirection() != wxLayout_RightToLeft) //don't change for RTL languages
- for (int i = 0; i < GetNumberCols(); ++i)
- if (getTypeAtPos(i) == xmlAccess::SIZE)
- {
- wxGridCellAttr* cellAttributes = GetOrCreateCellAttr(0, i);
- cellAttributes->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTRE);
- SetColAttr(i, cellAttributes);
- break;
- }
- //----------------------------------------------------------------------------------
-
- columnSettings.clear();
- if (attr.size() == 0)
- {
- //default settings:
- columnSettings = getDefaultColumnAttributes();
- }
- else
- {
- for (size_t i = 0; i < xmlAccess::COLUMN_TYPE_COUNT; ++i)
- {
- xmlAccess::ColumnAttrib newEntry;
-
- if (i < attr.size())
- newEntry = attr[i];
- else //fix corrupted data:
- {
- newEntry.type = static_cast<xmlAccess::ColumnTypes>(xmlAccess::COLUMN_TYPE_COUNT); //sort additional rows to the end
- newEntry.visible = false;
- newEntry.position = i;
- newEntry.width = 100;
- }
- columnSettings.push_back(newEntry);
- }
-
- std::sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByType);
- for (size_t i = 0; i < xmlAccess::COLUMN_TYPE_COUNT; ++i) //just be sure that each type exists only once
- columnSettings[i].type = static_cast<xmlAccess::ColumnTypes>(i);
-
- std::sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByPositionOnly);
- for (size_t i = 0; i < xmlAccess::COLUMN_TYPE_COUNT; ++i) //just be sure that positions are numbered correctly
- columnSettings[i].position = i;
- }
-
- std::sort(columnSettings.begin(), columnSettings.end(), xmlAccess::sortByPositionAndVisibility);
- std::vector<xmlAccess::ColumnTypes> newPositions;
- for (size_t i = 0; i < columnSettings.size() && columnSettings[i].visible; ++i) //hidden columns are sorted to the end of vector!
- newPositions.push_back(columnSettings[i].type);
-
- //set column positions
- if (getGridDataTableRim())
- getGridDataTableRim()->setupColumns(newPositions);
-
- //set column width (set them after setupColumns!)
- for (size_t i = 0; i < newPositions.size(); ++i)
- SetColSize(static_cast<int>(i), columnSettings[i].width);
-
- //--------------------------------------------------------------------------------------------------------
- //set special alignment for column "size"
- if (GetLayoutDirection() != wxLayout_RightToLeft) //don't change for RTL languages
- for (int i = 0; i < GetNumberCols(); ++i)
- if (getTypeAtPos(i) == xmlAccess::SIZE)
- {
- wxGridCellAttr* cellAttributes = GetOrCreateCellAttr(0, i);
- cellAttributes->SetAlignment(wxALIGN_RIGHT, wxALIGN_CENTRE);
- SetColAttr(i, cellAttributes); //make filesize right justified on grids
- break;
- }
-
- ClearSelection();
- ForceRefresh();
-}
-
-
-xmlAccess::ColumnTypes CustomGridRim::getTypeAtPos(size_t pos) const
-{
- if (getGridDataTableRim())
- return getGridDataTableRim()->getTypeAtPos(pos);
- else
- return xmlAccess::DIRECTORY;
-}
-
-
-wxString CustomGridRim::getTypeName(xmlAccess::ColumnTypes colType)
-{
- switch (colType)
- {
- case xmlAccess::FULL_PATH:
- return _("Full path");
- case xmlAccess::FILENAME:
- return _("Filename");
- case xmlAccess::REL_PATH:
- return _("Relative path");
- case xmlAccess::DIRECTORY:
- return _("Directory");
- case xmlAccess::SIZE:
- return _("Size");
- case xmlAccess::DATE:
- return _("Date");
- case xmlAccess::EXTENSION:
- return _("Extension");
- }
-
- return wxEmptyString; //dummy
-}
-
-
-void CustomGridRim::autoSizeColumns() //performance optimized column resizer (analog to wxGrid::AutoSizeColumns()
-{
- for (int col = 0; col < GetNumberCols(); ++col)
- {
- if (col < 0)
- return;
-
- int rowMax = -1;
- size_t lenMax = 0;
- for (int row = 0; row < GetNumberRows(); ++row)
- if (GetCellValue(row, col).size() > lenMax)
- {
- lenMax = GetCellValue(row, col).size();
- rowMax = row;
- }
-
- wxCoord extentMax = 0;
-
- //calculate width of (most likely) widest cell
- wxClientDC dc(GetGridWindow());
- if (rowMax > -1)
- {
- wxGridCellAttr* attr = GetCellAttr(rowMax, col);
- if (attr)
- {
- wxGridCellRenderer* renderer = attr->GetRenderer(this, rowMax, col);
- if (renderer)
- {
- const wxSize size = renderer->GetBestSize(*this, *attr, dc, rowMax, col);
- extentMax = std::max(extentMax, size.x);
- renderer->DecRef();
- }
- attr->DecRef();
- }
- }
-
- //consider column label
- dc.SetFont(GetLabelFont());
- wxCoord w = 0;
- wxCoord h = 0;
- dc.GetMultiLineTextExtent(GetColLabelValue(col), &w, &h );
- if (GetColLabelTextOrientation() == wxVERTICAL)
- w = h;
- extentMax = std::max(extentMax, w);
-
- extentMax += 15; //leave some space around text
-
- SetColSize(col, extentMax);
-
- }
- Refresh();
-}
-
-
-void CustomGridRim::enableFileIcons(const std::shared_ptr<IconBuffer>& iconBuffer)
-{
- iconBuffer_ = iconBuffer;
- SetDefaultRenderer(new GridCellRenderer(failedLoads, getGridDataTableRim(), iconBuffer)); //SetDefaultRenderer takes ownership!
-}
-
-
-std::pair<CustomGridRim::RowBegin, CustomGridRim::RowEnd> CustomGridRim::getVisibleRows()
-{
- int dummy = -1;
- int height = -1;
- GetGridWindow()->GetClientSize(&dummy, &height);
-
- if (height >= 0)
- {
- const int rowTop = mousePosToCell(wxPoint(0, 0)).first;
- int rowEnd = mousePosToCell(wxPoint(0, height)).first;
- if (rowEnd == -1) //when scrolling to the very end, there are a few border pixels that do not belong to any row
- rowEnd = GetNumberRows();
- else
- ++rowEnd;
-
- if (0 <= rowTop && rowTop <= rowEnd)
- return std::make_pair(rowTop, rowEnd); //"top" means here top of the screen => smaller value
- }
- return std::make_pair(0, 0);
-}
-
-
-inline
-CustomGridTableRim* CustomGridRim::getGridDataTableRim() const
-{
- return dynamic_cast<CustomGridTableRim*>(getGridDataTable()); //I'm tempted to use a static cast here...
-}
-
-
-void CustomGridRim::getIconsToBeLoaded(std::vector<Zstring>& newLoad) //loads all (not yet) drawn icons
-{
- //don't check too often! give worker thread some time to fetch data
-
- newLoad.clear();
-
- if (iconBuffer_.get())
- {
- const CustomGridTableRim* gridDataTable = getGridDataTableRim();
- if (!gridDataTable) return;
-
- const int totalCols = const_cast<CustomGridTableRim*>(gridDataTable)->GetNumberCols();
- const int totalRows = const_cast<CustomGridTableRim*>(gridDataTable)->GetNumberRows();
-
- //determine column
- const int colFilename = [&]() -> int
- {
- for (int k = 0; k < totalCols; ++k)
- if (gridDataTable->getTypeAtPos(k) == xmlAccess::FILENAME)
- return k;
- return -1;
- }();
- if (colFilename < 0)
- return;
-
- const auto rowsOnScreen = getVisibleRows();
-
- //loop over all visible rows
- const int firstRow = static_cast<int>(rowsOnScreen.first);
- const int rowNo = std::min(static_cast<int>(rowsOnScreen.second), totalRows) - firstRow;
-
- for (int i = 0; i < rowNo; ++i)
- {
- //alternate when adding rows: first, last, first + 1, last - 1 ... -> Icon buffer will then load reversely, i.e. from inside out
- const int currentRow = firstRow + (i % 2 == 0 ?
- i / 2 :
- rowNo - 1 - (i - 1) / 2);
-
- if (failedLoads.find(currentRow) != failedLoads.end()) //find failed attempts to load icon
- {
- const Zstring fileName = gridDataTable->getIconFile(currentRow);
- if (!fileName.empty())
- {
- //test if they are already loaded in buffer:
- if (iconBuffer_->requestFileIcon(fileName))
- {
- //exists in buffer: refresh Row
- RefreshCell(currentRow, colFilename); //do a *full* refresh for *every* failed load to update partial DC updates while scrolling
- failedLoads.erase(currentRow); //
- }
- else //not yet in buffer: mark for async. loading
- {
- newLoad.push_back(fileName);
- }
- }
- }
- }
- }
-}
-
-//----------------------------------------------------------------------------------------
-
-
-//update file icons periodically: use SINGLE instance to coordinate left and right grid at once
-IconUpdater::IconUpdater(CustomGridLeft* leftGrid, CustomGridRight* rightGrid) :
- m_leftGrid(leftGrid),
- m_rightGrid(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 in ms
-}
-
-
-IconUpdater::~IconUpdater() {}
-
-
-void IconUpdater::loadIconsAsynchronously(wxEvent& event) //loads all (not yet) drawn icons
-{
- std::vector<Zstring> iconsLeft;
- m_leftGrid->getIconsToBeLoaded(iconsLeft);
-
- std::vector<Zstring> newLoad;
- m_rightGrid->getIconsToBeLoaded(newLoad);
-
- //merge vectors
- newLoad.insert(newLoad.end(), iconsLeft.begin(), iconsLeft.end());
-
- if (m_leftGrid->iconBuffer_.get())
- m_leftGrid->iconBuffer_->setWorkload(newLoad);
-
- //event.Skip();
-}
-
-//----------------------------------------------------------------------------------------
-
-
-CustomGridLeft::CustomGridLeft(wxWindow* parent,
- wxWindowID id,
- const wxPoint& pos,
- const wxSize& size,
- long style,
- const wxString& name) :
- CustomGridRim(parent, id, pos, size, style, name)
-{
- GetGridWindow()->Connect(wxEVT_MOTION, wxMouseEventHandler(CustomGridLeft::OnMouseMovement), NULL, this); //row-based tooltip
-}
-
-
-bool CustomGridLeft::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode)
-{
- //use custom wxGridTableBase class for management of large sets of formatted data.
- //This is done in CreateGrid instead of SetTable method since source code is generated and wxFormbuilder invokes CreatedGrid by default.
- SetTable(new CustomGridTableLeft, true, wxGrid::wxGridSelectRows); //give ownership to wxGrid: gridDataTable is deleted automatically in wxGrid destructor
- return true;
-}
-
-
-void CustomGridLeft::initSettings(CustomGridLeft* gridLeft, //create connection with zen::GridView
- CustomGridMiddle* gridMiddle,
- CustomGridRight* gridRight,
- const zen::GridView* gridDataView)
-{
- //set underlying grid data
- assert(getGridDataTable());
- getGridDataTable()->setGridDataTable(gridDataView);
-
- CustomGridRim::setOtherGrid(gridRight);
-
- CustomGridRim::initSettings(gridLeft, gridMiddle, gridRight, gridDataView);
-}
-
-
-void CustomGridLeft::OnMouseMovement(wxMouseEvent& event)
-{
- CustomGridRim::setTooltip<LEFT_SIDE>(event);
- event.Skip();
-}
-
-
-CustomGridTable* CustomGridLeft::getGridDataTable() const
-{
- return static_cast<CustomGridTable*>(GetTable()); //one of the few cases where no dynamic_cast is required!
-}
-
-
-//----------------------------------------------------------------------------------------
-CustomGridRight::CustomGridRight(wxWindow* parent,
- wxWindowID id,
- const wxPoint& pos,
- const wxSize& size,
- long style,
- const wxString& name) :
- CustomGridRim(parent, id, pos, size, style, name)
-{
- GetGridWindow()->Connect(wxEVT_MOTION, wxMouseEventHandler(CustomGridRight::OnMouseMovement), NULL, this); //row-based tooltip
-}
-
-
-bool CustomGridRight::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode)
-{
- SetTable(new CustomGridTableRight, true, wxGrid::wxGridSelectRows); //give ownership to wxGrid: gridDataTable is deleted automatically in wxGrid destructor
- return true;
-}
-
-
-void CustomGridRight::initSettings(CustomGridLeft* gridLeft, //create connection with zen::GridView
- CustomGridMiddle* gridMiddle,
- CustomGridRight* gridRight,
- const zen::GridView* gridDataView)
-{
- //set underlying grid data
- assert(getGridDataTable());
- getGridDataTable()->setGridDataTable(gridDataView);
-
- CustomGridRim::setOtherGrid(gridLeft);
-
- CustomGridRim::initSettings(gridLeft, gridMiddle, gridRight, gridDataView);
-}
-
-
-void CustomGridRight::OnMouseMovement(wxMouseEvent& event)
-{
- CustomGridRim::setTooltip<RIGHT_SIDE>(event);
- event.Skip();
-}
-
-
-CustomGridTable* CustomGridRight::getGridDataTable() const
-{
- return static_cast<CustomGridTable*>(GetTable()); //one of the few cases where no dynamic_cast is required!
-}
-
-
-//----------------------------------------------------------------------------------------
-class GridCellRendererMiddle : public wxGridCellStringRenderer
-{
-public:
- GridCellRendererMiddle(const CustomGridMiddle& middleGrid) : m_gridMiddle(middleGrid) {};
-
- virtual void Draw(wxGrid& grid,
- wxGridCellAttr& attr,
- wxDC& dc,
- const wxRect& rect,
- int row, int col,
- bool isSelected);
-
-private:
- const CustomGridMiddle& m_gridMiddle;
-};
-
-
-//define new event types
-const wxEventType FFS_CHECK_ROWS_EVENT = wxNewEventType(); //attention! do NOT place in header to keep (generated) id unique!
-const wxEventType FFS_SYNC_DIRECTION_EVENT = wxNewEventType();
-
-const int CHECK_BOX_IMAGE = 11; //width of checkbox image
-const int CHECK_BOX_WIDTH = CHECK_BOX_IMAGE + 3; //width of first block
-
-// cell:
-// ----------------------------------
-// | checkbox | left | middle | right|
-// ----------------------------------
-
-
-CustomGridMiddle::CustomGridMiddle(wxWindow* parent,
- wxWindowID id,
- const wxPoint& pos,
- const wxSize& size,
- long style,
- const wxString& name) :
- CustomGrid(parent, id, pos, size, style, name),
- selectionRowBegin(-1),
- selectionPos(BLOCKPOS_CHECK_BOX),
- highlightedRow(-1),
- highlightedPos(BLOCKPOS_CHECK_BOX),
- toolTip(new CustomTooltip)
-{
- SetLayoutDirection(wxLayout_LeftToRight); //
- GetGridWindow()->SetLayoutDirection(wxLayout_LeftToRight); //avoid mirroring this dialog in RTL languages like Hebrew or Arabic
- GetGridColLabelWindow()->SetLayoutDirection(wxLayout_LeftToRight); //
-
- //connect events for dynamic selection of sync direction
- GetGridWindow()->Connect(wxEVT_MOTION, wxMouseEventHandler(CustomGridMiddle::OnMouseMovement), NULL, this);
- GetGridWindow()->Connect(wxEVT_LEAVE_WINDOW, wxMouseEventHandler(CustomGridMiddle::OnLeaveWindow), NULL, this);
- GetGridWindow()->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(CustomGridMiddle::OnLeftMouseUp), NULL, this);
- GetGridWindow()->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(CustomGridMiddle::OnLeftMouseDown), NULL, this);
-}
-
-
-CustomGridMiddle::~CustomGridMiddle() {}
-
-
-bool CustomGridMiddle::CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode)
-{
- SetTable(new CustomGridTableMiddle, true, wxGrid::wxGridSelectRows); //give ownership to wxGrid: gridDataTable is deleted automatically in wxGrid destructor
-
- //display checkboxes (representing bool values) if row is enabled for synchronization
- SetDefaultRenderer(new GridCellRendererMiddle(*this)); //SetDefaultRenderer takes ownership!
-
- return true;
-}
-
-
-void CustomGridMiddle::initSettings(CustomGridLeft* gridLeft, //create connection with zen::GridView
- CustomGridMiddle* gridMiddle,
- CustomGridRight* gridRight,
- const zen::GridView* gridDataView)
-{
- //set underlying grid data
- assert(getGridDataTable());
- getGridDataTable()->setGridDataTable(gridDataView);
-
-#ifdef FFS_LINUX //get rid of scrollbars; Linux: change policy for GtkScrolledWindow
- GtkWidget* gridWidget = wxWindow::m_widget;
- GtkScrolledWindow* scrolledWindow = GTK_SCROLLED_WINDOW(gridWidget);
- gtk_scrolled_window_set_policy(scrolledWindow, GTK_POLICY_NEVER, GTK_POLICY_NEVER);
-#endif
-
- CustomGrid::initSettings(gridLeft, gridMiddle, gridRight, gridDataView);
-}
-
-
-CustomGridTable* CustomGridMiddle::getGridDataTable() const
-{
- return static_cast<CustomGridTable*>(GetTable()); //one of the few cases where no dynamic_cast is required!
-}
-
-
-inline
-CustomGridTableMiddle* CustomGridMiddle::getGridDataTableMiddle() const
-{
- return static_cast<CustomGridTableMiddle*>(getGridDataTable());
-}
-
-
-#ifdef FFS_WIN //get rid of scrollbars; Windows: overwrite virtual method
-void CustomGridMiddle::SetScrollbar(int orientation, int position, int thumbSize, int range, bool refresh)
-{
- wxWindow::SetScrollbar(orientation, 0, 0, 0, refresh);
-}
-#endif
-
-
-void CustomGridMiddle::OnMouseMovement(wxMouseEvent& event)
-{
- const int rowOld = highlightedRow;
- const BlockPosition posOld = highlightedPos;
-
-
- if (selectionRowBegin == -1) //change highlightning only if currently not dragging mouse
- {
- highlightedRow = mousePosToRow(event.GetPosition(), &highlightedPos);
-
- if (rowOld != highlightedRow)
- {
- RefreshCell(highlightedRow, 0);
- RefreshCell(rowOld, 0);
- }
- else if (posOld != highlightedPos)
- RefreshCell(highlightedRow, 0);
-
- //handle tooltip
- showToolTip(highlightedRow, GetGridWindow()->ClientToScreen(event.GetPosition()));
- }
-
- event.Skip();
-}
-
-
-void CustomGridMiddle::OnLeaveWindow(wxMouseEvent& event)
-{
- highlightedRow = -1;
- highlightedPos = BLOCKPOS_CHECK_BOX;
- Refresh();
-
- //handle tooltip
- toolTip->hide();
-}
-
-
-void CustomGridMiddle::showToolTip(int rowNumber, wxPoint pos)
-{
- if (!getGridDataTableMiddle())
- return;
-
- const FileSystemObject* const fsObj = getGridDataTableMiddle()->getRawData(rowNumber);
- if (fsObj == NULL) //if invalid row...
- {
- toolTip->hide();
- return;
- }
-
- if (getGridDataTableMiddle()->syncPreviewIsActive()) //synchronization preview
- {
- const SyncOperation syncOp = fsObj->getSyncOperation();
- switch (syncOp)
- {
- case SO_CREATE_NEW_LEFT:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("createLeft")));
- break;
- case SO_CREATE_NEW_RIGHT:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("createRight")));
- break;
- case SO_DELETE_LEFT:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("deleteLeft")));
- break;
- case SO_DELETE_RIGHT:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("deleteRight")));
- break;
- case SO_OVERWRITE_LEFT:
- case SO_COPY_METADATA_TO_LEFT:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("updateLeft")));
- break;
- case SO_OVERWRITE_RIGHT:
- case SO_COPY_METADATA_TO_RIGHT:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("updateRight")));
- break;
- case SO_DO_NOTHING:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("none")));
- break;
- case SO_EQUAL:
- toolTip->show(getDescription(syncOp), pos, &GlobalResources::getImage(wxT("equal")));
- break;
- case SO_UNRESOLVED_CONFLICT:
- toolTip->show(fsObj->getSyncOpConflict(), pos, &GlobalResources::getImage(wxT("conflict")));
- break;
- };
- }
- else
- {
- const CompareFilesResult cmpRes = fsObj->getCategory();
- switch (cmpRes)
- {
- case FILE_LEFT_SIDE_ONLY:
- toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("leftOnly")));
- break;
- case FILE_RIGHT_SIDE_ONLY:
- toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("rightOnly")));
- break;
- case FILE_LEFT_NEWER:
- toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("leftNewer")));
- break;
- case FILE_RIGHT_NEWER:
- toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("rightNewer")));
- break;
- case FILE_DIFFERENT:
- toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("different")));
- break;
- case FILE_EQUAL:
- toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("equal")));
- break;
- case FILE_DIFFERENT_METADATA:
- toolTip->show(getDescription(cmpRes), pos, &GlobalResources::getImage(wxT("conflict")));
- break;
- case FILE_CONFLICT:
- toolTip->show(fsObj->getCatConflict(), pos, &GlobalResources::getImage(wxT("conflict")));
- break;
- }
- }
-}
-
-
-void CustomGridMiddle::OnLeftMouseDown(wxMouseEvent& event)
-{
- selectionRowBegin = mousePosToRow(event.GetPosition(), &selectionPos);
- event.Skip();
-}
-
-
-void CustomGridMiddle::OnLeftMouseUp(wxMouseEvent& event)
-{
- //int selRowEnd = mousePosToCell(event.GetPosition()).first;
- //-> use visibly marked rows instead! with wxWidgets 2.8.12 there is no other way than IsInSelection()
- int selRowEnd = -1;
- if (0 <= selectionRowBegin && selectionRowBegin < GetNumberRows())
- {
- for (int i = selectionRowBegin; i < GetNumberRows() && IsInSelection(i, 0); ++i)
- selRowEnd = i;
-
- if (selRowEnd == selectionRowBegin)
- for (int i = selectionRowBegin; i >= 0 && IsInSelection(i, 0); --i)
- selRowEnd = i;
- }
-
- if (0 <= selectionRowBegin && 0 <= selRowEnd)
- {
- switch (selectionPos)
- {
- case BLOCKPOS_CHECK_BOX:
- {
- //create a custom event
- FFSCheckRowsEvent evt(selectionRowBegin, selRowEnd);
- AddPendingEvent(evt);
- }
- break;
- case BLOCKPOS_LEFT:
- {
- //create a custom event
- FFSSyncDirectionEvent evt(selectionRowBegin, selRowEnd, SYNC_DIR_LEFT);
- AddPendingEvent(evt);
- }
- break;
- case BLOCKPOS_MIDDLE:
- {
- //create a custom event
- FFSSyncDirectionEvent evt(selectionRowBegin, selRowEnd, SYNC_DIR_NONE);
- AddPendingEvent(evt);
- }
- break;
- case BLOCKPOS_RIGHT:
- {
- //create a custom event
- FFSSyncDirectionEvent evt(selectionRowBegin, selRowEnd, SYNC_DIR_RIGHT);
- AddPendingEvent(evt);
- }
- break;
- }
- }
- selectionRowBegin = -1;
- selectionPos = BLOCKPOS_CHECK_BOX;
-
- ClearSelection();
- event.Skip();
-}
-
-
-int CustomGridMiddle::mousePosToRow(wxPoint pos, BlockPosition* block)
-{
- if (!getGridDataTableMiddle())
- return 0;
-
- int row = -1;
- int x = -1;
- int y = -1;
- CalcUnscrolledPosition( pos.x, pos.y, &x, &y );
- if (x >= 0 && y >= 0)
- {
- row = YToRow(y);
-
- //determine blockposition within cell (optional)
- if (block)
- {
- *block = BLOCKPOS_CHECK_BOX; //default
-
- if (row >= 0)
- {
- const FileSystemObject* const fsObj = getGridDataTableMiddle()->getRawData(row);
- if (fsObj != NULL && //if valid row...
- getGridDataTableMiddle()->syncPreviewIsActive() &&
- fsObj->getSyncOperation() != SO_EQUAL) //in sync-preview equal files shall be treated as in cmp result, i.e. as full checkbox
- {
- // cell:
- // ----------------------------------
- // | checkbox | left | middle | right|
- // ----------------------------------
-
- const wxRect rect = CellToRect(row, 0);
- if (rect.GetWidth() > CHECK_BOX_WIDTH)
- {
- const double blockWidth = (rect.GetWidth() - CHECK_BOX_WIDTH) / 3.0;
- if (rect.GetX() + CHECK_BOX_WIDTH <= x && x < rect.GetX() + rect.GetWidth())
- {
- if (x - (rect.GetX() + CHECK_BOX_WIDTH) < blockWidth)
- *block = BLOCKPOS_LEFT;
- else if (x - (rect.GetX() + CHECK_BOX_WIDTH) < 2 * blockWidth)
- *block = BLOCKPOS_MIDDLE;
- else
- *block = BLOCKPOS_RIGHT;
- }
- }
- }
- }
- }
- }
- return row;
-}
-
-
-void CustomGridMiddle::enableSyncPreview(bool value)
-{
- assert(getGridDataTableMiddle());
- getGridDataTableMiddle()->enableSyncPreview(value);
-
- if (value)
- GetGridColLabelWindow()->SetToolTip(_("Synchronization Preview"));
- else
- GetGridColLabelWindow()->SetToolTip(_("Comparison Result"));
-}
-
-
-void GridCellRendererMiddle::Draw(wxGrid& grid,
- wxGridCellAttr& attr,
- wxDC& dc,
- const wxRect& rect,
- int row, int col,
- bool isSelected)
-{
- //retrieve grid data
- const FileSystemObject* const fsObj = m_gridMiddle.getGridDataTableMiddle() ? m_gridMiddle.getGridDataTableMiddle()->getRawData(row) : NULL;
- if (fsObj != NULL) //if valid row...
- {
- 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
- rectShrinked.SetWidth(CHECK_BOX_WIDTH);
- wxGridCellRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected);
-
- //print checkbox into first block
- rectShrinked.SetX(rect.GetX() + 1);
-
- //HIGHLIGHTNING (checkbox):
- if (rowIsHighlighted &&
- m_gridMiddle.highlightedPos == CustomGridMiddle::BLOCKPOS_CHECK_BOX)
- {
- dc.DrawLabel(wxEmptyString, GlobalResources::getImage(fsObj->isActive() ?
- wxT("checkboxTrueFocus") :
- wxT("checkboxFalseFocus")), rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
- }
- else //default
- dc.DrawLabel(wxEmptyString, GlobalResources::getImage(fsObj->isActive() ?
- wxT("checkboxTrue") :
- wxT("checkboxFalse")), rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
-
- //clean remaining block of rect that will receive image of checkbox/directions
- rectShrinked.SetWidth(rect.GetWidth() - CHECK_BOX_WIDTH);
- rectShrinked.SetX(rect.GetX() + CHECK_BOX_WIDTH);
- wxGridCellRenderer::Draw(grid, attr, dc, rectShrinked, row, col, isSelected);
-
- //print remaining block
- if (m_gridMiddle.getGridDataTableMiddle()->syncPreviewIsActive()) //synchronization preview
- {
- //print sync direction into second block
-
- //HIGHLIGHTNING (sync direction):
- if (rowIsHighlighted &&
- m_gridMiddle.highlightedPos != CustomGridMiddle::BLOCKPOS_CHECK_BOX) //don't allow changing direction for "=="-files
- switch (m_gridMiddle.highlightedPos)
- {
- case CustomGridMiddle::BLOCKPOS_CHECK_BOX:
- break;
- case CustomGridMiddle::BLOCKPOS_LEFT:
- dc.DrawLabel(wxEmptyString, getSyncOpImage(fsObj->testSyncOperation(SYNC_DIR_LEFT)), rectShrinked, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
- break;
- case CustomGridMiddle::BLOCKPOS_MIDDLE:
- dc.DrawLabel(wxEmptyString, getSyncOpImage(fsObj->testSyncOperation(SYNC_DIR_NONE)), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- case CustomGridMiddle::BLOCKPOS_RIGHT:
- dc.DrawLabel(wxEmptyString, getSyncOpImage(fsObj->testSyncOperation(SYNC_DIR_RIGHT)), rectShrinked, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
- break;
- }
- else //default
- {
- const wxBitmap& syncOpIcon = getSyncOpImage(fsObj->getSyncOperation());
- dc.DrawLabel(wxEmptyString, syncOpIcon, rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- }
- }
- else //comparison results view
- {
- switch (fsObj->getCategory())
- {
- case FILE_LEFT_SIDE_ONLY:
- dc.DrawLabel(wxEmptyString, GlobalResources::getImage(wxT("leftOnlySmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- case FILE_RIGHT_SIDE_ONLY:
- dc.DrawLabel(wxEmptyString, GlobalResources::getImage(wxT("rightOnlySmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- case FILE_LEFT_NEWER:
- dc.DrawLabel(wxEmptyString, GlobalResources::getImage(wxT("leftNewerSmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- case FILE_RIGHT_NEWER:
- dc.DrawLabel(wxEmptyString, GlobalResources::getImage(wxT("rightNewerSmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- case FILE_DIFFERENT:
- dc.DrawLabel(wxEmptyString, GlobalResources::getImage(wxT("differentSmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- case FILE_EQUAL:
- dc.DrawLabel(wxEmptyString, GlobalResources::getImage(wxT("equalSmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- case FILE_CONFLICT:
- case FILE_DIFFERENT_METADATA:
- dc.DrawLabel(wxEmptyString, GlobalResources::getImage(wxT("conflictSmall")), rectShrinked, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
- break;
- }
- }
-
- return;
- }
- }
-
- //fallback
- wxGridCellStringRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
-}
-
-
-//this method is called when grid view changes: useful for parallel updating of multiple grids
-void CustomGridMiddle::alignOtherGrids(CustomGrid* gridLeft, CustomGrid* gridMiddle, CustomGrid* gridRight)
-{
- int x = 0;
- int y = 0;
- GetViewStart(&x, &y);
- gridLeft->Scroll(-1, y);
- gridRight->Scroll(-1, y);
-}
-
-
-void CustomGridMiddle::DrawColLabel(wxDC& dc, int col)
-{
- CustomGrid::DrawColLabel(dc, col);
-
- if (!getGridDataTableMiddle())
- return;
-
- const wxRect rect(GetColLeft(col), 0, GetColWidth(col), GetColLabelSize());
-
- if (getGridDataTableMiddle()->syncPreviewIsActive())
- dc.DrawLabel(wxEmptyString, GlobalResources::getImage(wxT("syncViewSmall")), rect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL);
- else
- dc.DrawLabel(wxEmptyString, GlobalResources::getImage(wxT("cmpViewSmall")), rect, wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL);
-}
-
-
-const wxBitmap& zen::getSyncOpImage(SyncOperation syncOp)
-{
- switch (syncOp) //evaluate comparison result and sync direction
- {
- case SO_CREATE_NEW_LEFT:
- return GlobalResources::getImage(wxT("createLeftSmall"));
- case SO_CREATE_NEW_RIGHT:
- return GlobalResources::getImage(wxT("createRightSmall"));
- case SO_DELETE_LEFT:
- return GlobalResources::getImage(wxT("deleteLeftSmall"));
- case SO_DELETE_RIGHT:
- return GlobalResources::getImage(wxT("deleteRightSmall"));
- case SO_OVERWRITE_RIGHT:
- case SO_COPY_METADATA_TO_RIGHT:
- return GlobalResources::getImage(wxT("updateRightSmall"));
- case SO_OVERWRITE_LEFT:
- case SO_COPY_METADATA_TO_LEFT:
- return GlobalResources::getImage(wxT("updateLeftSmall"));
- case SO_DO_NOTHING:
- return GlobalResources::getImage(wxT("noneSmall"));
- case SO_EQUAL:
- return GlobalResources::getImage(wxT("equalSmall"));
- case SO_UNRESOLVED_CONFLICT:
- return GlobalResources::getImage(wxT("conflictSmall"));
- }
-
- return wxNullBitmap; //dummy
-}
-
diff --git a/library/custom_grid.h b/library/custom_grid.h
deleted file mode 100644
index a1bce692..00000000
--- a/library/custom_grid.h
+++ /dev/null
@@ -1,370 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#ifndef CUSTOMGRID_H_INCLUDED
-#define CUSTOMGRID_H_INCLUDED
-
-#include <vector>
-#include <wx/grid.h>
-#include "process_xml.h"
-#include <memory>
-#include <set>
-#include "../file_hierarchy.h"
-#include "icon_buffer.h"
-
-
-class CustomGridTable;
-class CustomGridTableRim;
-class CustomGridTableLeft;
-class CustomGridTableRight;
-class CustomGridTableMiddle;
-class GridCellRendererMiddle;
-class wxTimer;
-class CustomTooltip;
-class CustomGridRim;
-class CustomGridLeft;
-class CustomGridMiddle;
-class CustomGridRight;
-
-
-namespace zen
-{
-class GridView;
-
-const wxBitmap& getSyncOpImage(SyncOperation syncOp);
-}
-//##################################################################################
-
-/*
-class hierarchy:
- CustomGrid
- /|\
- ____________|____________
- | |
- CustomGridRim |
- /|\ |
- ________|_______ |
- | | |
-CustomGridLeft CustomGridRight CustomGridMiddle
-*/
-
-class CustomGrid : public wxGrid
-{
-public:
- CustomGrid(wxWindow* parent,
- wxWindowID id,
- const wxPoint& pos = wxDefaultPosition,
- const wxSize& size = wxDefaultSize,
- long style = wxWANTS_CHARS,
- const wxString& name = wxGridNameStr);
-
- virtual ~CustomGrid() {}
-
- virtual void initSettings(CustomGridLeft* gridLeft, //create connection with zen::GridView
- CustomGridMiddle* gridMiddle,
- CustomGridRight* gridRight,
- const zen::GridView* gridDataView);
-
- void release(); //release connection to zen::GridView
-
- std::set<size_t> getAllSelectedRows() const;
-
- //set sort direction indicator on UI
- typedef int SortColumn;
-
- //notify wxGrid that underlying table size has changed
- virtual void updateGridSizes();
-
- enum SortDirection
- {
- ASCENDING,
- DESCENDING
- };
- typedef std::pair<SortColumn, SortDirection> SortMarker;
- void setSortMarker(SortMarker marker);
-
- bool isLeadGrid() const;
-
- void setIconManager(const std::shared_ptr<zen::IconBuffer>& iconBuffer);
-
-protected:
- void RefreshCell(int row, int col);
- virtual void DrawColLabel(wxDC& dc, int col);
- std::pair<int, int> mousePosToCell(wxPoint pos); //returns (row/column) pair
-
- virtual CustomGridTable* getGridDataTable() const = 0;
-
-private:
- void onGridAccess(wxEvent& event);
-
- //this method is called when grid view changes: useful for parallel updating of multiple grids
- void OnPaintGrid(wxEvent& event);
-
- virtual void alignOtherGrids(CustomGrid* gridLeft, CustomGrid* gridMiddle, CustomGrid* gridRight) = 0;
-
- void adjustGridHeights(wxEvent& event);
- virtual void enableFileIcons(const std::shared_ptr<zen::IconBuffer>& iconBuffer) = 0;
-
- CustomGrid* m_gridLeft;
- CustomGrid* m_gridMiddle;
- CustomGrid* m_gridRight;
-
- bool isLeading; //identify grid that has user focus
-
- SortMarker m_marker;
-};
-
-
-class GridCellRenderer;
-
-
-//-----------------------------------------------------------
-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);
- ~IconUpdater();
-
-private:
- void loadIconsAsynchronously(wxEvent& event); //loads all (not yet) drawn icons
-
- CustomGridRim* m_leftGrid;
- CustomGridRim* m_rightGrid;
-
- std::unique_ptr<wxTimer> m_timer; //user timer event to periodically update icons: better than idle event because also active when scrolling! :)
-};
-
-
-//############## SPECIALIZATIONS ###################
-class CustomGridRim : public CustomGrid
-{
- friend class IconUpdater;
- friend class GridCellRenderer;
-
-public:
- CustomGridRim(wxWindow* parent,
- wxWindowID id,
- const wxPoint& pos,
- const wxSize& size,
- long style,
- const wxString& name);
-
- //set visibility, position and width of columns
- static xmlAccess::ColumnAttributes getDefaultColumnAttributes();
- xmlAccess::ColumnAttributes getColumnAttributes();
- void setColumnAttributes(const xmlAccess::ColumnAttributes& attr);
-
- xmlAccess::ColumnTypes getTypeAtPos(size_t pos) const;
- static wxString getTypeName(xmlAccess::ColumnTypes colType);
-
- void autoSizeColumns(); //performance optimized column resizer
-
- virtual void updateGridSizes();
-
-protected:
- template <zen::SelectedSide side>
- void setTooltip(const wxMouseEvent& event);
-
- void setOtherGrid(CustomGridRim* other); //call during initialization!
-
-private:
- CustomGridTableRim* getGridDataTableRim() const;
- virtual void enableFileIcons(const std::shared_ptr<zen::IconBuffer>& iconBuffer);
-
- void OnResizeColumn(wxGridSizeEvent& event);
-
- //this method is called when grid view changes: useful for parallel updating of multiple grids
- virtual void alignOtherGrids(CustomGrid* gridLeft, CustomGrid* gridMiddle, CustomGrid* gridRight);
-
- //asynchronous icon loading
- void getIconsToBeLoaded(std::vector<Zstring>& newLoad); //loads all (not yet) drawn icons
-
- typedef size_t RowBegin;
- typedef size_t RowEnd;
- std::pair<RowBegin, RowEnd> getVisibleRows(); //return [first, last) number pair
-
- typedef size_t RowNumber;
- typedef std::set<RowNumber> FailedIconLoad;
- FailedIconLoad failedLoads; //save status of last icon load when drawing on GUI
-
- std::shared_ptr<zen::IconBuffer> iconBuffer_;
-
- xmlAccess::ColumnAttributes columnSettings; //set visibility, position and width of columns
- CustomGridRim* otherGrid; //sibling grid on other side
-};
-
-
-class CustomGridLeft : public CustomGridRim
-{
-public:
- CustomGridLeft(wxWindow* parent,
- wxWindowID id,
- const wxPoint& pos = wxDefaultPosition,
- const wxSize& size = wxDefaultSize,
- long style = wxWANTS_CHARS,
- const wxString& name = wxGridNameStr);
-
- virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells);
-
- virtual void initSettings(CustomGridLeft* gridLeft, //create connection with zen::GridView
- CustomGridMiddle* gridMiddle,
- CustomGridRight* gridRight,
- const zen::GridView* gridDataView);
-
-private:
- void OnMouseMovement(wxMouseEvent& event);
- virtual CustomGridTable* getGridDataTable() const;
-};
-
-
-class CustomGridRight : public CustomGridRim
-{
-public:
- CustomGridRight(wxWindow* parent,
- wxWindowID id,
- const wxPoint& pos = wxDefaultPosition,
- const wxSize& size = wxDefaultSize,
- long style = wxWANTS_CHARS,
- const wxString& name = wxGridNameStr);
-
- virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells);
-
- virtual void initSettings(CustomGridLeft* gridLeft, //create connection with zen::GridView
- CustomGridMiddle* gridMiddle,
- CustomGridRight* gridRight,
- const zen::GridView* gridDataView);
-
-private:
- void OnMouseMovement(wxMouseEvent& event);
- virtual CustomGridTable* getGridDataTable() const;
-};
-
-
-class CustomGridMiddle : public CustomGrid
-{
- friend class GridCellRendererMiddle;
-
-public:
- CustomGridMiddle(wxWindow* parent,
- wxWindowID id,
- const wxPoint& pos = wxDefaultPosition,
- const wxSize& size = wxDefaultSize,
- long style = wxWANTS_CHARS,
- const wxString& name = wxGridNameStr);
-
- ~CustomGridMiddle();
-
- virtual bool CreateGrid(int numRows, int numCols, wxGrid::wxGridSelectionModes selmode = wxGrid::wxGridSelectCells);
-
- virtual void initSettings(CustomGridLeft* gridLeft, //create connection with zen::GridView
- CustomGridMiddle* gridMiddle,
- CustomGridRight* gridRight,
- const zen::GridView* gridDataView);
-
- void enableSyncPreview(bool value);
-
-private:
- virtual CustomGridTable* getGridDataTable() const;
- CustomGridTableMiddle* getGridDataTableMiddle() const;
-
- virtual void enableFileIcons(const std::shared_ptr<zen::IconBuffer>& iconBuffer) {};
-#ifdef FFS_WIN //get rid of scrollbars; Windows: overwrite virtual method
- virtual void SetScrollbar(int orientation, int position, int thumbSize, int range, bool refresh = true);
-#endif
-
- //this method is called when grid view changes: useful for parallel updating of multiple grids
- virtual void alignOtherGrids(CustomGrid* gridLeft, CustomGrid* gridMiddle, CustomGrid* gridRight);
-
- virtual void DrawColLabel(wxDC& dc, int col);
-
- void OnMouseMovement(wxMouseEvent& event);
- void OnLeaveWindow(wxMouseEvent& event);
- 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
- {
- BLOCKPOS_CHECK_BOX,
- BLOCKPOS_LEFT,
- BLOCKPOS_MIDDLE,
- BLOCKPOS_RIGHT
- };
- int mousePosToRow(const wxPoint pos, BlockPosition* block = NULL);
-
- //variables for selecting sync direction
- int selectionRowBegin;
- BlockPosition selectionPos;
-
- //variables for highlightning on mouse-over
- int highlightedRow;
- BlockPosition highlightedPos;
-
- std::unique_ptr<CustomTooltip> toolTip;
-};
-
-//custom events for middle grid:
-
-//--------------------------------------------------------------------------------------------
-//(UN-)CHECKING ROWS FROM SYNCHRONIZATION
-
-extern const wxEventType FFS_CHECK_ROWS_EVENT; //define new event type
-
-class FFSCheckRowsEvent : public wxCommandEvent
-{
-public:
- FFSCheckRowsEvent(const int from, const int to) :
- wxCommandEvent(FFS_CHECK_ROWS_EVENT),
- rowFrom(from),
- rowTo(to) {}
-
- virtual wxEvent* Clone() const
- {
- return new FFSCheckRowsEvent(rowFrom, rowTo);
- }
-
- const int rowFrom;
- const int rowTo;
-};
-
-typedef void (wxEvtHandler::*FFSCheckRowsEventFunction)(FFSCheckRowsEvent&);
-
-#define FFSCheckRowsEventHandler(func) \
- (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(FFSCheckRowsEventFunction, &func)
-
-//--------------------------------------------------------------------------------------------
-//SELECTING SYNC DIRECTION
-
-extern const wxEventType FFS_SYNC_DIRECTION_EVENT; //define new event type
-
-class FFSSyncDirectionEvent : public wxCommandEvent
-{
-public:
- FFSSyncDirectionEvent(const int from, const int to, const zen::SyncDirection dir) :
- wxCommandEvent(FFS_SYNC_DIRECTION_EVENT),
- rowFrom(from),
- rowTo(to),
- direction(dir) {}
-
- virtual wxEvent* Clone() const
- {
- return new FFSSyncDirectionEvent(rowFrom, rowTo, direction);
- }
-
- const int rowFrom;
- const int rowTo;
- const zen::SyncDirection direction;
-};
-
-typedef void (wxEvtHandler::*FFSSyncDirectionEventFunction)(FFSSyncDirectionEvent&);
-
-#define FFSSyncDirectionEventHandler(func) \
- (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(FFSSyncDirectionEventFunction, &func)
-
-
-#endif // CUSTOMGRID_H_INCLUDED
diff --git a/library/db_file.cpp b/library/db_file.cpp
deleted file mode 100644
index 268e411e..00000000
--- a/library/db_file.cpp
+++ /dev/null
@@ -1,598 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#include "db_file.h"
-#include <wx/wfstream.h>
-#include <wx/zstream.h>
-#include <wx/mstream.h>
-#include "../shared/global_func.h"
-#include "../shared/file_error.h"
-#include "../shared/string_conv.h"
-#include "../shared/file_handling.h"
-#include "../shared/serialize.h"
-#include "../shared/file_io.h"
-#include "../shared/loki/ScopeGuard.h"
-#include "../shared/i18n.h"
-#include <boost/bind.hpp>
-
-#ifdef FFS_WIN
-#include <wx/msw/wrapwin.h> //includes "windows.h"
-#include "../shared/long_path_prefix.h"
-#endif
-
-using namespace zen;
-
-
-namespace
-{
-//-------------------------------------------------------------------------------------------------------------------------------
-const char FILE_FORMAT_DESCR[] = "FreeFileSync";
-const int FILE_FORMAT_VER = 7;
-//-------------------------------------------------------------------------------------------------------------------------------
-
-
-template <SelectedSide side> inline
-Zstring getDBFilename(const BaseDirMapping& baseMap, bool tempfile = false)
-{
- //Linux and Windows builds are binary incompatible: char/wchar_t case, sensitive/insensitive
- //32 and 64 bit db files ARE designed to be binary compatible!
- //Give db files different names.
- //make sure they end with ".ffs_db". These files will not be included into comparison when located in base sync directories
-#ifdef FFS_WIN
- Zstring dbname = Zstring(Zstr("sync")) + (tempfile ? Zstr(".tmp") : Zstr("")) + SYNC_DB_FILE_ENDING;
-#elif defined FFS_LINUX
- //files beginning with dots are hidden e.g. in Nautilus
- Zstring dbname = Zstring(Zstr(".sync")) + (tempfile ? Zstr(".tmp") : Zstr("")) + SYNC_DB_FILE_ENDING;
-#endif
-
- return baseMap.getBaseDirPf<side>() + dbname;
-}
-
-
-
-class FileInputStreamDB : public FileInputStream
-{
-public:
- FileInputStreamDB(const Zstring& filename) : //throw FileError
- FileInputStream(filename)
- {
- //read FreeFileSync file identifier
- char formatDescr[sizeof(FILE_FORMAT_DESCR)] = {};
- Read(formatDescr, sizeof(formatDescr)); //throw FileError
-
- if (!std::equal(FILE_FORMAT_DESCR, FILE_FORMAT_DESCR + sizeof(FILE_FORMAT_DESCR), formatDescr))
- throw FileError(_("Incompatible synchronization database format:") + " \n" + "\"" + filename + "\"");
- }
-
-private:
-};
-
-
-class FileOutputStreamDB : public FileOutputStream
-{
-public:
- FileOutputStreamDB(const Zstring& filename) : //throw FileError
- FileOutputStream(filename)
- {
- //write FreeFileSync file identifier
- Write(FILE_FORMAT_DESCR, sizeof(FILE_FORMAT_DESCR)); //throw FileError
- }
-
-private:
-};
-}
-//#######################################################################################################################################
-
-
-class ReadDirInfo : public zen::ReadInputStream
-{
-public:
- ReadDirInfo(wxInputStream& stream, const wxString& errorObjName, DirInformation& dirInfo) : ReadInputStream(stream, errorObjName)
- {
- //|-------------------------------------------------------------------------------------
- //| ensure 32/64 bit portability: use fixed size data types only e.g. boost::uint32_t |
- //|-------------------------------------------------------------------------------------
-
- //read filter settings -> currently not required, but persisting it doesn't hurt
- dirInfo.filter = HardFilter::loadFilter(getStream());
- check();
-
- //start recursion
- execute(dirInfo.baseDirContainer);
- }
-
-private:
- void execute(DirContainer& dirCont) const
- {
- while (readNumberC<bool>())
- readSubFile(dirCont);
-
- while (readNumberC<bool>())
- readSubLink(dirCont);
-
- while (readNumberC<bool>())
- readSubDirectory(dirCont);
- }
-
- void readSubFile(DirContainer& dirCont) const
- {
- //attention: order of function argument evaluation is undefined! So do it one after the other...
- const Zstring shortName = readStringC<Zstring>(); //file name
-
- const boost::int64_t modTime = readNumberC<boost::int64_t>();
- const boost::uint64_t fileSize = readNumberC<boost::uint64_t>();
-
- //const util::FileID fileIdentifier(stream_);
- //check();
-
- dirCont.addSubFile(shortName,
- FileDescriptor(modTime, fileSize));
- }
-
-
- void readSubLink(DirContainer& dirCont) const
- {
- //attention: order of function argument evaluation is undefined! So do it one after the other...
- const Zstring shortName = readStringC<Zstring>(); //file name
- const boost::int64_t modTime = readNumberC<boost::int64_t>();
- const Zstring targetPath = readStringC<Zstring>(); //file name
- const LinkDescriptor::LinkType linkType = static_cast<LinkDescriptor::LinkType>(readNumberC<boost::int32_t>());
-
- dirCont.addSubLink(shortName,
- LinkDescriptor(modTime, targetPath, linkType));
- }
-
-
- void readSubDirectory(DirContainer& dirCont) const
- {
- const Zstring shortName = readStringC<Zstring>(); //directory name
- DirContainer& subDir = dirCont.addSubDir(shortName);
- execute(subDir); //recurse
- }
-};
-
-namespace
-{
-typedef std::string UniqueId;
-typedef std::shared_ptr<std::vector<char> > MemoryStreamPtr; //byte stream representing DirInformation
-typedef std::map<UniqueId, MemoryStreamPtr> StreamMapping; //list of streams ordered by session UUID
-}
-
-class ReadFileStream : public zen::ReadInputStream
-{
-public:
- ReadFileStream(wxInputStream& stream, const wxString& filename, StreamMapping& streamList) : ReadInputStream(stream, filename)
- {
- //|-------------------------------------------------------------------------------------
- //| ensure 32/64 bit portability: used fixed size data types only e.g. boost::uint32_t |
- //|-------------------------------------------------------------------------------------
-
- boost::int32_t version = readNumberC<boost::int32_t>();
-
- if (version != FILE_FORMAT_VER) //read file format version
- throw FileError(_("Incompatible synchronization database format:") + " \n" + "\"" + filename.c_str() + "\"");
-
- streamList.clear();
-
- boost::uint32_t dbCount = readNumberC<boost::uint32_t>(); //number of databases: one for each sync-pair
- while (dbCount-- != 0)
- {
- //DB id of partner databases
- const CharArray tmp2 = readArrayC();
- const std::string sessionID(tmp2->begin(), tmp2->end());
-
- CharArray buffer = readArrayC(); //read db-entry stream (containing DirInformation)
-
- streamList.insert(std::make_pair(sessionID, buffer));
- }
- }
-};
-
-namespace
-{
-StreamMapping loadStreams(const Zstring& filename) //throw FileError
-{
- if (!zen::fileExists(filename))
- throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + " \n\n" +
- _("One of the FreeFileSync database files is not yet existing:") + " \n" +
- "\"" + filename + "\"");
-
- try
- {
- //read format description (uncompressed)
- FileInputStreamDB uncompressed(filename); //throw FileError
-
- wxZlibInputStream input(uncompressed, wxZLIB_ZLIB);
-
- StreamMapping streamList;
- ReadFileStream(input, toWx(filename), streamList);
- return streamList;
- }
- catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file
- {
- throw FileError(_("Error reading from synchronization database:") + " (bad_alloc)");
- }
-}
-
-
-DirInfoPtr parseStream(const std::vector<char>& stream, const Zstring& fileName) //throw FileError -> return value always bound!
-{
- try
- {
- //read streams into DirInfo
- auto dirInfo = std::make_shared<DirInformation>();
- wxMemoryInputStream buffer(&stream[0], stream.size()); //convert char-array to inputstream: no copying, ownership not transferred
- ReadDirInfo(buffer, toWx(fileName), *dirInfo); //throw FileError
- return dirInfo;
- }
- catch (const std::bad_alloc&) //this is most likely caused by a corrupted database file
- {
- throw FileError(_("Error reading from synchronization database:") + " (bad_alloc)");
- }
-}
-}
-
-
-std::pair<DirInfoPtr, DirInfoPtr> zen::loadFromDisk(const BaseDirMapping& baseMapping) //throw FileError
-{
- const Zstring fileNameLeft = getDBFilename<LEFT_SIDE>(baseMapping);
- const Zstring fileNameRight = getDBFilename<RIGHT_SIDE>(baseMapping);
-
- //read file data: list of session ID + DirInfo-stream
- const StreamMapping streamListLeft = ::loadStreams(fileNameLeft); //throw FileError
- const StreamMapping streamListRight = ::loadStreams(fileNameRight); //throw FileError
-
- //find associated session: there can be at most one session within intersection of left and right ids
- StreamMapping::const_iterator streamLeft = streamListLeft .end();
- StreamMapping::const_iterator streamRight = streamListRight.end();
- for (auto iterLeft = streamListLeft.begin(); iterLeft != streamListLeft.end(); ++iterLeft)
- {
- auto iterRight = streamListRight.find(iterLeft->first);
- if (iterRight != streamListRight.end())
- {
- streamLeft = iterLeft;
- streamRight = iterRight;
- break;
- }
- }
-
- if (streamLeft == streamListLeft .end() ||
- streamRight == streamListRight.end() ||
- !streamLeft ->second.get() ||
- !streamRight->second.get())
- throw FileErrorDatabaseNotExisting(_("Initial synchronization:") + " \n\n" +
- _("Database files do not share a common synchronization session:") + " \n" +
- "\"" + fileNameLeft + "\"\n" +
- "\"" + fileNameRight + "\"");
- //read streams into DirInfo
- DirInfoPtr dirInfoLeft = parseStream(*streamLeft ->second, fileNameLeft); //throw FileError
- DirInfoPtr dirInfoRight = parseStream(*streamRight->second, fileNameRight); //throw FileError
-
- return std::make_pair(dirInfoLeft, dirInfoRight);
-}
-
-
-//-------------------------------------------------------------------------------------------------------------------------
-template <SelectedSide side>
-class SaveDirInfo : public WriteOutputStream
-{
-public:
- SaveDirInfo(const BaseDirMapping& baseMapping, const DirContainer* oldDirInfo, const wxString& errorObjName, wxOutputStream& stream) : WriteOutputStream(errorObjName, stream)
- {
- //save filter settings
- baseMapping.getFilter()->saveFilter(getStream());
- check();
-
- //start recursion
- execute(baseMapping, oldDirInfo);
- }
-
-private:
- void execute(const HierarchyObject& hierObj, const DirContainer* oldDirInfo)
- {
- std::for_each(hierObj.refSubFiles().begin(), hierObj.refSubFiles().end(), boost::bind(&SaveDirInfo::processFile, this, _1, oldDirInfo));
- writeNumberC<bool>(false); //mark last entry
- std::for_each(hierObj.refSubLinks().begin(), hierObj.refSubLinks().end(), boost::bind(&SaveDirInfo::processLink, this, _1, oldDirInfo));
- writeNumberC<bool>(false); //mark last entry
- std::for_each(hierObj.refSubDirs ().begin(), hierObj.refSubDirs ().end(), boost::bind(&SaveDirInfo::processDir, this, _1, oldDirInfo));
- writeNumberC<bool>(false); //mark last entry
- }
-
- void processFile(const FileMapping& fileMap, const DirContainer* oldParentDir)
- {
- if (fileMap.getCategory() == FILE_EQUAL) //data in sync: write current state
- {
- if (!fileMap.isEmpty<side>())
- {
- writeNumberC<bool>(true); //mark beginning of entry
- writeStringC(fileMap.getShortName<side>()); //save respecting case! (Windows)
- writeNumberC<boost::int64_t >(to<boost::int64_t>(fileMap.getLastWriteTime<side>())); //last modification time
- writeNumberC<boost::uint64_t>(to<boost::uint64_t>(fileMap.getFileSize<side>())); //filesize
- }
- }
- else //not in sync: reuse last synchronous state
- {
- if (oldParentDir) //no data is also a "synchronous state"!
- {
- auto iter = oldParentDir->files.find(fileMap.getObjShortName());
- if (iter != oldParentDir->files.end())
- {
- writeNumberC<bool>(true); //mark beginning of entry
- writeStringC(iter->first); //save respecting case! (Windows)
- writeNumberC<boost::int64_t >(to<boost::int64_t>(iter->second.lastWriteTimeRaw)); //last modification time
- writeNumberC<boost::uint64_t>(to<boost::uint64_t>(iter->second.fileSize)); //filesize
- }
- }
- }
- }
-
- void processLink(const SymLinkMapping& linkObj, const DirContainer* oldParentDir)
- {
- if (linkObj.getLinkCategory() == SYMLINK_EQUAL) //data in sync: write current state
- {
- if (!linkObj.isEmpty<side>())
- {
- writeNumberC<bool>(true); //mark beginning of entry
- writeStringC(linkObj.getShortName<side>()); //save respecting case! (Windows)
- writeNumberC<boost::int64_t>(to<boost::int64_t>(linkObj.getLastWriteTime<side>())); //last modification time
- writeStringC(linkObj.getTargetPath<side>());
- writeNumberC<boost::int32_t>(linkObj.getLinkType<side>());
- }
- }
- else //not in sync: reuse last synchronous state
- {
- if (oldParentDir) //no data is also a "synchronous state"!
- {
- auto iter = oldParentDir->links.find(linkObj.getObjShortName());
- if (iter != oldParentDir->links.end())
- {
- writeNumberC<bool>(true); //mark beginning of entry
- writeStringC(iter->first); //save respecting case! (Windows)
- writeNumberC<boost::int64_t>(to<boost::int64_t>(iter->second.lastWriteTimeRaw)); //last modification time
- writeStringC(iter->second.targetPath);
- writeNumberC<boost::int32_t>(iter->second.type);
- }
- }
- }
- }
-
- void processDir(const DirMapping& dirMap, const DirContainer* oldParentDir)
- {
- const DirContainer* oldDir = NULL;
- const Zstring* oldDirName = NULL;
- if (oldParentDir) //no data is also a "synchronous state"!
- {
- auto iter = oldParentDir->dirs.find(dirMap.getObjShortName());
- if (iter != oldParentDir->dirs.end())
- {
- oldDirName = &iter->first;
- oldDir = &iter->second;
- }
- }
-
- CompareDirResult cat = dirMap.getDirCategory();
-
- if (cat == DIR_EQUAL) //data in sync: write current state
- {
- if (!dirMap.isEmpty<side>())
- {
- writeNumberC<bool>(true); //mark beginning of entry
- writeStringC(dirMap.getShortName<side>()); //save respecting case! (Windows)
- execute(dirMap, oldDir); //recurse
- }
- }
- else //not in sync: reuse last synchronous state
- {
- if (oldDir)
- {
- writeNumberC<bool>(true); //mark beginning of entry
- writeStringC(*oldDirName); //save respecting case! (Windows)
- execute(dirMap, oldDir); //recurse
- return;
- }
- //no data is also a "synchronous state"!
-
- //else: not in sync AND no "last synchronous state"
- //we cannot simply skip the whole directory, since sub-items might be in sync
- //Example: directories on left and right differ in case while sub-files are equal
- switch (cat)
- {
- case DIR_LEFT_SIDE_ONLY: //sub-items cannot be in sync
- break;
- case DIR_RIGHT_SIDE_ONLY: //sub-items cannot be in sync
- break;
- case DIR_EQUAL:
- assert(false);
- break;
- case DIR_DIFFERENT_METADATA:
- writeNumberC<bool>(true);
- writeStringC(dirMap.getShortName<side>());
- //ATTENTION: strictly this is a violation of the principle of reporting last synchronous state!
- //however in this case this will result in "last sync unsuccessful" for this directory within <automatic> algorithm, which is fine
- execute(dirMap, oldDir); //recurse and save sub-items which are in sync
- break;
- }
- }
- }
-};
-
-
-class WriteFileStream : public WriteOutputStream
-{
-public:
- WriteFileStream(const StreamMapping& streamList, const wxString& filename, wxOutputStream& stream) : WriteOutputStream(filename, stream)
- {
- //save file format version
- writeNumberC<boost::int32_t>(FILE_FORMAT_VER);
-
- writeNumberC<boost::uint32_t>(static_cast<boost::uint32_t>(streamList.size())); //number of database records: one for each sync-pair
-
- for (StreamMapping::const_iterator i = streamList.begin(); i != streamList.end(); ++i)
- {
- //sync session id
- writeArrayC(std::vector<char>(i->first.begin(), i->first.end()));
-
- //write DirInformation stream
- writeArrayC(*(i->second));
- }
- }
-};
-
-
-//save/load DirContainer
-void saveFile(const StreamMapping& streamList, const Zstring& filename) //throw FileError
-{
- {
- //write format description (uncompressed)
- FileOutputStreamDB uncompressed(filename); //throw FileError
-
- wxZlibOutputStream output(uncompressed, 4, wxZLIB_ZLIB);
- /* 4 - best compromise between speed and compression: (scanning 200.000 objects)
- 0 (uncompressed) 8,95 MB - 422 ms
- 2 2,07 MB - 470 ms
- 4 1,87 MB - 500 ms
- 6 1,77 MB - 613 ms
- 9 (maximal compression) 1,74 MB - 3330 ms */
-
- WriteFileStream(streamList, toWx(filename), output);
- }
- //(try to) hide database file
-#ifdef FFS_WIN
- ::SetFileAttributes(zen::applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_HIDDEN);
-#endif
-}
-
-
-bool equalEntry(const MemoryStreamPtr& lhs, const MemoryStreamPtr& rhs)
-{
- if (!lhs.get() || !rhs.get())
- return lhs.get() == rhs.get();
-
- return *lhs == *rhs;
-}
-
-
-void zen::saveToDisk(const BaseDirMapping& baseMapping) //throw FileError
-{
- //transactional behaviour! write to tmp files first
- const Zstring dbNameLeftTmp = getDBFilename<LEFT_SIDE >(baseMapping, true);
- const Zstring dbNameRightTmp = getDBFilename<RIGHT_SIDE>(baseMapping, true);
-
- const Zstring dbNameLeft = getDBFilename<LEFT_SIDE >(baseMapping);
- const Zstring dbNameRight = getDBFilename<RIGHT_SIDE>(baseMapping);
-
- //delete old tmp file, if necessary -> throws if deletion fails!
- removeFile(dbNameLeftTmp); //
- removeFile(dbNameRightTmp); //throw FileError
-
- //(try to) load old database files...
- StreamMapping streamListLeft;
- StreamMapping streamListRight;
-
- try //read file data: list of session ID + DirInfo-stream
- {
- streamListLeft = ::loadStreams(dbNameLeft);
- }
- catch (FileError&) {} //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
- try
- {
- streamListRight = ::loadStreams(dbNameRight);
- }
- catch (FileError&) {}
-
- //find associated session: there can be at most one session within intersection of left and right ids
- StreamMapping::iterator streamLeft = streamListLeft .end();
- StreamMapping::iterator streamRight = streamListRight.end();
- for (auto iterLeft = streamListLeft.begin(); iterLeft != streamListLeft.end(); ++iterLeft)
- {
- auto iterRight = streamListRight.find(iterLeft->first);
- if (iterRight != streamListRight.end())
- {
- streamLeft = iterLeft;
- streamRight = iterRight;
- break;
- }
- }
-
- //(try to) read old DirInfo
- DirInfoPtr oldDirInfoLeft;
- DirInfoPtr oldDirInfoRight;
- try
- {
- if (streamLeft != streamListLeft .end() &&
- streamRight != streamListRight.end() &&
- streamLeft ->second.get() &&
- streamRight->second.get())
- {
- oldDirInfoLeft = parseStream(*streamLeft ->second, dbNameLeft); //throw FileError
- oldDirInfoRight = parseStream(*streamRight->second, dbNameRight); //throw FileError
- }
- }
- catch (FileError&)
- {
- //if error occurs: just overwrite old file! User is already informed about issues right after comparing!
- oldDirInfoLeft .reset(); //read both or none!
- oldDirInfoRight.reset(); //
- }
-
- //create new database entries
- MemoryStreamPtr newStreamLeft = std::make_shared<std::vector<char>>();
- {
- wxMemoryOutputStream buffer;
- const DirContainer* oldDir = oldDirInfoLeft.get() ? &oldDirInfoLeft->baseDirContainer : NULL;
- SaveDirInfo<LEFT_SIDE>(baseMapping, oldDir, toWx(dbNameLeft), buffer);
- newStreamLeft->resize(buffer.GetSize()); //convert output stream to char-array
- buffer.CopyTo(&(*newStreamLeft)[0], buffer.GetSize()); //
- }
-
- MemoryStreamPtr newStreamRight = std::make_shared<std::vector<char>>();
- {
- wxMemoryOutputStream buffer;
- const DirContainer* oldDir = oldDirInfoRight.get() ? &oldDirInfoRight->baseDirContainer : NULL;
- SaveDirInfo<RIGHT_SIDE>(baseMapping, oldDir, toWx(dbNameRight), buffer);
- newStreamRight->resize(buffer.GetSize()); //convert output stream to char-array
- buffer.CopyTo(&(*newStreamRight)[0], buffer.GetSize()); //
- }
-
- //check if there is some work to do at all
- {
- const bool updateRequiredLeft = streamLeft == streamListLeft .end() || !equalEntry(newStreamLeft, streamLeft ->second);
- const bool updateRequiredRight = streamRight == streamListRight.end() || !equalEntry(newStreamRight, streamRight->second);
- //some users monitor the *.ffs_db file with RTS => don't touch the file if it isnt't strictly needed
- if (!updateRequiredLeft && !updateRequiredRight)
- return;
- }
-
- //create/update DirInfo-streams
- std::string sessionID = util::generateGUID();
-
- //erase old session data
- if (streamLeft != streamListLeft.end())
- streamListLeft.erase(streamLeft);
- if (streamRight != streamListRight.end())
- streamListRight.erase(streamRight);
-
- //fill in new
- streamListLeft .insert(std::make_pair(sessionID, newStreamLeft));
- streamListRight.insert(std::make_pair(sessionID, newStreamRight));
-
- //write (temp-) files...
- Loki::ScopeGuard guardTempFileLeft = Loki::MakeGuard(&zen::removeFile, dbNameLeftTmp);
- saveFile(streamListLeft, dbNameLeftTmp); //throw FileError
-
- Loki::ScopeGuard guardTempFileRight = Loki::MakeGuard(&zen::removeFile, dbNameRightTmp);
- saveFile(streamListRight, dbNameRightTmp); //throw FileError
-
- //operation finished: rename temp files -> this should work transactionally:
- //if there were no write access, creation of temp files would have failed
- removeFile(dbNameLeft);
- removeFile(dbNameRight);
- renameFile(dbNameLeftTmp, dbNameLeft); //throw FileError;
- renameFile(dbNameRightTmp, dbNameRight); //throw FileError;
-
- guardTempFileLeft. Dismiss(); //no need to delete temp file anymore
- guardTempFileRight.Dismiss(); //
-}
diff --git a/library/db_file.h b/library/db_file.h
deleted file mode 100644
index 188d7d92..00000000
--- a/library/db_file.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#ifndef DBFILE_H_INCLUDED
-#define DBFILE_H_INCLUDED
-
-#include "../shared/file_error.h"
-#include "../file_hierarchy.h"
-
-namespace zen
-{
-const Zstring SYNC_DB_FILE_ENDING = Zstr(".ffs_db");
-
-void saveToDisk(const BaseDirMapping& baseMapping); //throw FileError
-
-struct DirInformation
-{
- HardFilter::FilterRef filter; //filter settings (used when retrieving directory data)
- DirContainer baseDirContainer; //hierarchical directory information
-};
-typedef std::shared_ptr<const DirInformation> DirInfoPtr;
-
-DEFINE_NEW_FILE_ERROR(FileErrorDatabaseNotExisting);
-
-std::pair<DirInfoPtr, DirInfoPtr> loadFromDisk(const BaseDirMapping& baseMapping); //throw FileError, FileErrorDatabaseNotExisting -> return value always bound!
-}
-
-#endif // DBFILE_H_INCLUDED
diff --git a/library/detect_renaming.cpp b/library/detect_renaming.cpp
deleted file mode 100644
index 39e7eb4b..00000000
--- a/library/detect_renaming.cpp
+++ /dev/null
@@ -1,285 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#include "detect_renaming.h"
-#include <map>
-#include <vector>
-#include <boost/bind.hpp>
-
-using namespace FreeFileSync;
-
-/*detect renamed files:
-Example:
- X -> |_| Create right
-|_| -> Y Delete right
-
-is detected as:
-
-Rename Y to X on right
-
-Algorithm:
-----------
-DB-file left ---filename, Metadata(=:MD)---> DB-file right
- /|\ |
- | fileID, MD
- fileID, MD |
- | \|/
- X Y
-
-*/
-
-
-class FindDBAssoc
-{
- /*
- load and associate db-files by filename and metadata(size, date)
- fileID, MD |-> fileID
- */
-public:
- struct AssocKey
- {
- AssocKey(const Utility::FileID& fileId,
- const wxLongLong& lastWriteTimeRaw,
- const wxULongLong& fileSize);
-
- bool operator<(const AssocKey& other) const;
-
- Utility::FileID fileId_;
- wxLongLong lastWriteTimeRaw_;
- wxULongLong fileSize_;
- };
-
- FindDBAssoc(const FreeFileSync::BaseDirMapping& baseMapping,
- std::map<AssocKey, Utility::FileID>& assocDBLeftToRight);
-
-private:
- void recurse(const DirContainer& leftSide, const DirContainer& rightSide);
-
- std::map<AssocKey, Utility::FileID>& assocDBLeftToRight_; //-->
-};
-
-
-inline
-FindDBAssoc::AssocKey::AssocKey(const Utility::FileID& fileId,
- const wxLongLong& lastWriteTimeRaw,
- const wxULongLong& fileSize) :
- fileId_(fileId),
- lastWriteTimeRaw_(lastWriteTimeRaw),
- fileSize_(fileSize) {}
-
-
-inline
-bool FindDBAssoc::AssocKey::operator<(const AssocKey& other) const
-{
- if (fileId_ != other.fileId_)
- return fileId_ < other.fileId_;
-
- if (lastWriteTimeRaw_ != other.lastWriteTimeRaw_)
- return lastWriteTimeRaw_ < other.lastWriteTimeRaw_;
-
- return fileSize_ < other.fileSize_;
-}
-
-
-FindDBAssoc::FindDBAssoc(const FreeFileSync::BaseDirMapping& baseMapping,
- std::map<AssocKey, Utility::FileID>& assocDBLeftToRight) : assocDBLeftToRight_(assocDBLeftToRight)
-{
- try
- {
- std::pair<FreeFileSync::DirInfoPtr, FreeFileSync::DirInfoPtr> dbInfo =
- FreeFileSync::loadFromDisk(baseMapping); //throw (FileError)
-
- recurse(dbInfo.first->baseDirContainer,
- dbInfo.second->baseDirContainer);
- }
- catch (...) {} //swallow...
-}
-
-
-void FindDBAssoc::recurse(const DirContainer& leftSide, const DirContainer& rightSide)
-{
- for (DirContainer::SubFileList::const_iterator i = leftSide.getSubFiles().begin(); i != leftSide.getSubFiles().end(); ++i)
- {
- const FileDescriptor& fileDescrI = i->second.getData();
- if (!fileDescrI.fileIdentifier.isNull()) //fileIdentifier may be NULL
- {
- const DirContainer::SubFileList::const_iterator j = rightSide.getSubFiles().find(i->first);
-
- //find files that exist on left and right
- if (j != rightSide.getSubFiles().end())
- {
- const FileDescriptor& fileDescrJ = j->second.getData();
- if (!fileDescrJ.fileIdentifier.isNull()) //fileIdentifier may be NULL
- {
- if ( fileDescrI.lastWriteTimeRaw == fileDescrJ.lastWriteTimeRaw &&
- fileDescrI.fileSize == fileDescrJ.fileSize)
- {
- assocDBLeftToRight_[AssocKey(fileDescrI.fileIdentifier,
- fileDescrI.lastWriteTimeRaw,
- fileDescrI.fileSize)] = fileDescrJ.fileIdentifier;
- }
- }
- }
- }
- }
-
- //-----------------------------------------------------------------------------------------------
- for (DirContainer::SubDirList::const_iterator i = leftSide.getSubDirs().begin(); i != leftSide.getSubDirs().end(); ++i)
- {
- const DirContainer::SubDirList::const_iterator j = rightSide.getSubDirs().find(i->first);
-
- //directories that exist on both sides
- if (j != rightSide.getSubDirs().end())
- {
- recurse(i->second, j->second); //recurse into subdirectories
- }
- }
-}
-
-
-
-class FindRenameCandidates
-{
-public:
- FindRenameCandidates(FreeFileSync::BaseDirMapping& baseMapping)
- {
- FindDBAssoc(baseMapping,
- assocDBLeftToRight);
-
- if (!assocDBLeftToRight.empty())
- recurse(baseMapping);
- }
-
- void getRenameCandidates(std::vector<std::pair<FileMapping*, FileMapping*> >& renameOnLeft,
- std::vector<std::pair<FileMapping*, FileMapping*> >& renameOnRight);
-
-private:
- void recurse(HierarchyObject& hierObj)
- {
- //files
- std::for_each(hierObj.subFiles.begin(), hierObj.subFiles.end(),
- boost::bind(&FindRenameCandidates::processFile, this, _1));
-
- //directories
- std::for_each(hierObj.subDirs.begin(), hierObj.subDirs.end(),
- boost::bind(&FindRenameCandidates::recurse, this, _1));//recursion
- }
-
- void processFile(FileMapping& fileObj)
- {
- switch (fileObj.getSyncOperation()) //evaluate comparison result and sync direction
- {
- case SO_CREATE_NEW_LEFT:
- if (!fileObj.getFileID<RIGHT_SIDE>().isNull()) //fileIdentifier may be NULL
- createLeft[FindDBAssoc::AssocKey(fileObj.getFileID<RIGHT_SIDE>(),
- fileObj.getLastWriteTime<RIGHT_SIDE>(),
- fileObj.getFileSize<RIGHT_SIDE>())] = &fileObj;
- break;
-
- case SO_CREATE_NEW_RIGHT:
- if (!fileObj.getFileID<LEFT_SIDE>().isNull()) //fileIdentifier may be NULL
- createRight.push_back(&fileObj);
- break;
-
- case SO_DELETE_LEFT:
- if (!fileObj.getFileID<LEFT_SIDE>().isNull()) //fileIdentifier may be NULL
- deleteLeft.push_back(&fileObj);
- break;
-
- case SO_DELETE_RIGHT:
- if (!fileObj.getFileID<RIGHT_SIDE>().isNull()) //fileIdentifier may be NULL
- deleteRight[FindDBAssoc::AssocKey(fileObj.getFileID<RIGHT_SIDE>(),
- fileObj.getLastWriteTime<RIGHT_SIDE>(),
- fileObj.getFileSize<RIGHT_SIDE>())] = &fileObj;
- break;
-
- case SO_OVERWRITE_RIGHT:
- case SO_OVERWRITE_LEFT:
- case SO_DO_NOTHING:
- case SO_UNRESOLVED_CONFLICT:
- break;
- }
-
- }
-
-
- std::vector<FileMapping*> createRight; //pointer always bound!
- std::vector<FileMapping*> deleteLeft; //
- // |
- // \|/
- std::map<FindDBAssoc::AssocKey, Utility::FileID> assocDBLeftToRight;
- // |
- // \|/
- std::map<FindDBAssoc::AssocKey, FileMapping*> deleteRight; //pointer always bound!
- std::map<FindDBAssoc::AssocKey, FileMapping*> createLeft; //
-
-};
-
-
-
-void FindRenameCandidates::getRenameCandidates(
- std::vector<std::pair<FileMapping*, FileMapping*> >& renameOnLeft,
- std::vector<std::pair<FileMapping*, FileMapping*> >& renameOnRight)
-{
- for (std::vector<FileMapping*>::const_iterator crRightIter = createRight.begin();
- crRightIter != createRight.end();
- ++crRightIter)
- {
- const FindDBAssoc::AssocKey assocDbKey((*crRightIter)->getFileID<LEFT_SIDE>(),
- (*crRightIter)->getLastWriteTime<LEFT_SIDE>(),
- (*crRightIter)->getFileSize<LEFT_SIDE>());
-
- const std::map<FindDBAssoc::AssocKey, Utility::FileID>::const_iterator assocDBIter =
- assocDBLeftToRight.find(assocDbKey);
-
- if (assocDBIter != assocDBLeftToRight.end())
- {
- std::map<FindDBAssoc::AssocKey, FileMapping*>::const_iterator delRightIter =
- deleteRight.find(FindDBAssoc::AssocKey(assocDBIter->second, //FileID of right side
- assocDbKey.lastWriteTimeRaw_,
- assocDbKey.fileSize_));
-
- if (delRightIter != deleteRight.end())
- {
- renameOnRight.push_back(std::make_pair(*crRightIter, delRightIter->second));
- }
- }
- }
- //------------------------------------------------------------------------------------------------
- for (std::vector<FileMapping*>::const_iterator delLeftIter = deleteLeft.begin();
- delLeftIter != deleteLeft.end();
- ++delLeftIter)
- {
- const FindDBAssoc::AssocKey assocDbKey((*delLeftIter)->getFileID<LEFT_SIDE>(),
- (*delLeftIter)->getLastWriteTime<LEFT_SIDE>(),
- (*delLeftIter)->getFileSize<LEFT_SIDE>());
-
- const std::map<FindDBAssoc::AssocKey, Utility::FileID>::const_iterator assocDBIter =
- assocDBLeftToRight.find(assocDbKey);
-
- if (assocDBIter != assocDBLeftToRight.end())
- {
- std::map<FindDBAssoc::AssocKey, FileMapping*>::const_iterator createLeftIter =
- createLeft.find(FindDBAssoc::AssocKey(assocDBIter->second, //FileID of right side
- assocDbKey.lastWriteTimeRaw_,
- assocDbKey.fileSize_));
-
- if (createLeftIter != createLeft.end())
- {
- renameOnLeft.push_back(std::make_pair(createLeftIter->second, *delLeftIter));
- }
- }
- }
-}
-
-
-void FreeFileSync::getRenameCandidates(FreeFileSync::BaseDirMapping& baseMapping, //in
- std::vector<std::pair<CreateOnLeft, DeleteOnLeft> >& renameOnLeft, //out
- std::vector<std::pair<CreateOnRight, DeleteOnRight> >& renameOnRight) //out throw()!
-{
- FindRenameCandidates(baseMapping).getRenameCandidates(renameOnLeft, renameOnRight);
-}
-
diff --git a/library/detect_renaming.h b/library/detect_renaming.h
deleted file mode 100644
index e94927c0..00000000
--- a/library/detect_renaming.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#ifndef DETECTRENAMING_H_INCLUDED
-#define DETECTRENAMING_H_INCLUDED
-
-#include "../file_hierarchy.h"
-
-
-//identify a file "create and delete"-operation as a file renaming!
-
-namespace zen
-{
-typedef FileMapping* CreateOnLeft;
-typedef FileMapping* DeleteOnLeft;
-typedef FileMapping* CreateOnRight;
-typedef FileMapping* DeleteOnRight;
-void getRenameCandidates(zen::BaseDirMapping& baseMapping, //in
- std::vector<std::pair<CreateOnLeft, DeleteOnLeft> >& renameOnLeft, //out
- std::vector<std::pair<CreateOnRight, DeleteOnRight> >& renameOnRight); //out throw()!
-}
-
-#endif // DETECTRENAMING_H_INCLUDED
diff --git a/library/dir_exist_async.h b/library/dir_exist_async.h
deleted file mode 100644
index cab82aa2..00000000
--- a/library/dir_exist_async.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#ifndef DIR_EXIST_HEADER_08173281673432158067342132467183267
-#define DIR_EXIST_HEADER_08173281673432158067342132467183267
-
-#include "../shared/check_exist.h"
-#include "status_handler.h"
-#include "../shared/file_error.h"
-#include "../shared/i18n.h"
-
-//dir existence checking may hang for non-existent network drives => run asynchronously and update UI!
-namespace
-{
-using namespace zen; //restricted to unnamed namespace!
-
-bool dirExistsUpdating(const Zstring& dirname, ProcessCallback& procCallback)
-{
- using namespace util;
-
- std::wstring statusText = _("Searching for directory %x...");
- replace(statusText, L"%x", std::wstring(L"\"") + dirname + L"\"", false);
- procCallback.reportStatus(statusText);
-
- auto ft = dirExistsAsync(dirname);
- while (!ft.timed_wait(boost::posix_time::milliseconds(UI_UPDATE_INTERVAL)))
- procCallback.requestUiRefresh(); //may throw!
- return ft.get();
-}
-}
-
-#endif //DIR_EXIST_HEADER_08173281673432158067342132467183267
diff --git a/library/dir_lock.cpp b/library/dir_lock.cpp
deleted file mode 100644
index 7feb51ff..00000000
--- a/library/dir_lock.cpp
+++ /dev/null
@@ -1,599 +0,0 @@
-#include "dir_lock.h"
-#include <utility>
-#include <wx/utils.h>
-#include <wx/timer.h>
-#include <wx/log.h>
-#include <wx/msgdlg.h>
-#include <memory>
-#include <boost/weak_ptr.hpp>
-#include "../shared/string_conv.h"
-#include "../shared/i18n.h"
-#include "../shared/last_error.h"
-#include "../shared/boost_thread_wrap.h" //include <boost/thread.hpp>
-#include "../shared/loki/ScopeGuard.h"
-#include "../shared/guid.h"
-#include "../shared/file_io.h"
-#include "../shared/assert_static.h"
-#include "../shared/serialize.h"
-#include "../shared/build_info.h"
-#include "../shared/int64.h"
-#include "../shared/file_handling.h"
-
-#ifdef FFS_WIN
-#include <tlhelp32.h>
-#include <wx/msw/wrapwin.h> //includes "windows.h"
-#include "../shared/long_path_prefix.h"
-
-#elif defined FFS_LINUX
-#include <sys/stat.h>
-#include <cerrno>
-#include <unistd.h>
-#endif
-
-using namespace zen;
-using namespace std::rel_ops;
-
-
-namespace
-{
-const size_t EMIT_LIFE_SIGN_INTERVAL = 5000; //show life sign; unit [ms]
-const size_t POLL_LIFE_SIGN_INTERVAL = 6000; //poll for life sign; unit [ms]
-const size_t DETECT_EXITUS_INTERVAL = 30000; //assume abandoned lock; unit [ms]
-
-const char LOCK_FORMAT_DESCR[] = "FreeFileSync";
-const int LOCK_FORMAT_VER = 1; //lock file format version
-}
-
-//worker thread
-class LifeSigns
-{
-public:
- LifeSigns(const Zstring& lockfilename) : //throw()!!! siehe SharedDirLock()
- lockfilename_(lockfilename) {} //thread safety: make deep copy!
-
- void operator()() const //thread entry
- {
- try
- {
- while (true)
- {
- boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(EMIT_LIFE_SIGN_INTERVAL)); //interruption point!
-
- //actual work
- emitLifeSign(); //throw ()
- }
- }
- catch (const std::exception& e) //exceptions must be catched per thread
- {
- wxSafeShowMessage(wxString(_("An exception occurred!")) + wxT("(Dirlock)"), wxString::FromAscii(e.what())); //simple wxMessageBox won't do for threads
- }
- }
-
- void emitLifeSign() const //try to append one byte...; throw()
- {
- const char buffer[1] = {' '};
-
-#ifdef FFS_WIN
- //ATTENTION: setting file pointer IS required! => use CreateFile/FILE_GENERIC_WRITE + SetFilePointerEx!
- //although CreateFile/FILE_APPEND_DATA without SetFilePointerEx works locally, it MAY NOT work on some network shares creating a 4 gig file!!!
-
- const HANDLE fileHandle = ::CreateFile(applyLongPathPrefix(lockfilename_.c_str()).c_str(),
- GENERIC_READ | GENERIC_WRITE, //use both when writing over network, see comment in file_io.cpp
- FILE_SHARE_READ,
- 0,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (fileHandle == INVALID_HANDLE_VALUE)
- return;
- LOKI_ON_BLOCK_EXIT2(::CloseHandle(fileHandle));
-
- const LARGE_INTEGER moveDist = {};
- if (!::SetFilePointerEx(fileHandle, //__in HANDLE hFile,
- moveDist, //__in LARGE_INTEGER liDistanceToMove,
- NULL, //__out_opt PLARGE_INTEGER lpNewFilePointer,
- FILE_END)) //__in DWORD dwMoveMethod
- return;
-
- DWORD bytesWritten = 0;
- ::WriteFile(fileHandle, //__in HANDLE hFile,
- buffer, //__out LPVOID lpBuffer,
- 1, //__in DWORD nNumberOfBytesToRead,
- &bytesWritten, //__out_opt LPDWORD lpNumberOfBytesWritten,
- NULL); //__inout_opt LPOVERLAPPED lpOverlapped
-
-#elif defined FFS_LINUX
- const int fileHandle = ::open(lockfilename_.c_str(), O_WRONLY | O_APPEND); //O_EXCL contains a race condition on NFS file systems: http://linux.die.net/man/2/open
- if (fileHandle == -1)
- return;
- LOKI_ON_BLOCK_EXIT2(::close(fileHandle));
-
- const ssize_t bytesWritten = ::write(fileHandle, buffer, 1);
- (void)bytesWritten;
-#endif
- }
-
-private:
- const Zstring lockfilename_; //thread local! atomic ref-count => binary value-type semantics!
-};
-
-
-namespace
-{
-UInt64 getLockFileSize(const Zstring& filename) //throw FileError, ErrorNotExisting
-{
-#ifdef FFS_WIN
- WIN32_FIND_DATA fileInfo = {};
- const HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(filename).c_str(), &fileInfo);
- if (searchHandle == INVALID_HANDLE_VALUE)
- {
- const DWORD lastError = ::GetLastError();
-
- std::wstring errorMessage = _("Error reading file attributes:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted(lastError);
-
- if (lastError == ERROR_FILE_NOT_FOUND ||
- lastError == ERROR_PATH_NOT_FOUND)
- throw ErrorNotExisting(errorMessage);
- else
- throw FileError(errorMessage);
- }
-
- ::FindClose(searchHandle);
-
- return zen::UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh);
-
-#elif defined FFS_LINUX
- struct stat fileInfo = {};
- if (::stat(filename.c_str(), &fileInfo) != 0) //follow symbolic links
- {
- const int lastError = errno;
-
- std::wstring errorMessage = _("Error reading file attributes:") + "\n\"" + filename + "\"" + "\n\n" + getLastErrorFormatted(lastError);
-
- if (lastError == ENOENT)
- throw ErrorNotExisting(errorMessage);
- else
- throw FileError(errorMessage);
- }
-
- return zen::UInt64(fileInfo.st_size);
-#endif
-}
-
-
-Zstring deleteAbandonedLockName(const Zstring& lockfilename) //make sure to NOT change file ending!
-{
- const size_t pos = lockfilename.rfind(FILE_NAME_SEPARATOR); //search from end
- return pos == Zstring::npos ? Zstr("Del.") + lockfilename :
- Zstring(lockfilename.c_str(), pos + 1) + //include path separator
- Zstr("Del.") +
- lockfilename.AfterLast(FILE_NAME_SEPARATOR); //returns the whole string if ch not found
-}
-
-
-namespace
-{
-//read string from file stream
-inline
-std::string readString(wxInputStream& stream) //throw std::exception
-{
- const auto strLength = readPOD<boost::uint32_t>(stream);
- std::string output;
- if (strLength > 0)
- {
- output.resize(strLength); //throw std::bad_alloc
- stream.Read(&output[0], strLength);
- }
- return output;
-}
-
-
-inline
-void writeString(wxOutputStream& stream, const std::string& str) //write string to filestream
-{
- writePOD(stream, static_cast<boost::uint32_t>(str.length()));
- stream.Write(str.c_str(), str.length());
-}
-
-
-std::string getComputerId() //returns empty string on error
-{
- const wxString fhn = ::wxGetFullHostName();
- if (fhn.empty()) return std::string();
-#ifdef FFS_WIN
- return "Windows " + std::string(fhn.ToUTF8());
-#elif defined FFS_LINUX
- return "Linux " + std::string(fhn.ToUTF8());
-#endif
-}
-
-
-struct LockInformation
-{
- LockInformation()
- {
- lockId = util::generateGUID();
-#ifdef FFS_WIN
- procDescr.processId = ::GetCurrentProcessId();
-#elif defined FFS_LINUX
- procDescr.processId = ::getpid();
-#endif
- procDescr.computerId = getComputerId();
- }
-
- LockInformation(wxInputStream& stream) //read
- {
- char formatDescr[sizeof(LOCK_FORMAT_DESCR)] = {};
- stream.Read(formatDescr, sizeof(LOCK_FORMAT_DESCR)); //file format header
- const int lockFileVersion = readPOD<boost::int32_t>(stream); //
- (void)lockFileVersion;
-
- //some format checking here?
-
- lockId = readString(stream);
- procDescr.processId = static_cast<ProcessId>(readPOD<boost::uint64_t>(stream)); //possible loss of precision (32/64 bit process) covered by buildId
- procDescr.computerId = readString(stream);
- }
-
- void toStream(wxOutputStream& stream) const //write
- {
- assert_static(sizeof(ProcessId) <= sizeof(boost::uint64_t)); //ensure portability
-
- stream.Write(LOCK_FORMAT_DESCR, sizeof(LOCK_FORMAT_DESCR));
- writePOD<boost::int32_t>(stream, LOCK_FORMAT_VER);
-
- writeString(stream, lockId);
- writePOD<boost::uint64_t>(stream, procDescr.processId);
- writeString(stream, procDescr.computerId);
- }
-
-#ifdef FFS_WIN
- typedef DWORD ProcessId; //same size on 32 and 64 bit windows!
-#elif defined FFS_LINUX
- typedef pid_t ProcessId;
-#endif
-
- std::string lockId; //16 byte UUID
-
- struct ProcessDescription
- {
- ProcessId processId;
- std::string computerId;
- } procDescr;
-};
-
-
-//true: process not available, false: cannot say anything
-enum ProcessStatus
-{
- PROC_STATUS_NOT_RUNNING,
- PROC_STATUS_RUNNING,
- PROC_STATUS_ITS_US,
- PROC_STATUS_NO_IDEA
-};
-ProcessStatus getProcessStatus(const LockInformation::ProcessDescription& procDescr)
-{
- if (procDescr.computerId != getComputerId() ||
- procDescr.computerId.empty()) //both names are empty
- return PROC_STATUS_NO_IDEA; //lock owned by different computer
-
-#ifdef FFS_WIN
- if (procDescr.processId == ::GetCurrentProcessId()) //may seem obscure, but it's possible: a lock file is "stolen" and put back while the program is running
- return PROC_STATUS_ITS_US;
-
- //note: ::OpenProcess() is no option as it may successfully return for crashed processes!
- HANDLE snapshot = ::CreateToolhelp32Snapshot(
- TH32CS_SNAPPROCESS, //__in DWORD dwFlags,
- 0); //__in DWORD th32ProcessID
- if (snapshot == INVALID_HANDLE_VALUE)
- return PROC_STATUS_NO_IDEA;
- LOKI_ON_BLOCK_EXIT2(::CloseHandle(snapshot));
-
- PROCESSENTRY32 processEntry = {};
- processEntry.dwSize = sizeof(processEntry);
-
- if (!::Process32First(snapshot, //__in HANDLE hSnapshot,
- &processEntry)) //__inout LPPROCESSENTRY32 lppe
- return PROC_STATUS_NO_IDEA;
- do
- {
- if (processEntry.th32ProcessID == procDescr.processId)
- return PROC_STATUS_RUNNING; //process still running
- }
- while (::Process32Next(snapshot, &processEntry));
-
- return PROC_STATUS_NOT_RUNNING;
-
-#elif defined FFS_LINUX
- if (procDescr.processId == ::getpid()) //may seem obscure, but it's possible: a lock file is "stolen" and put back while the program is running
- return PROC_STATUS_ITS_US;
-
- if (procDescr.processId <= 0 || procDescr.processId >= 65536)
- return PROC_STATUS_NO_IDEA; //invalid process id
-
- return zen::dirExists(Zstr("/proc/") + Zstring::fromNumber(procDescr.processId)) ? PROC_STATUS_RUNNING : PROC_STATUS_NOT_RUNNING;
-#endif
-}
-
-
-void writeLockInfo(const Zstring& lockfilename) //throw FileError
-{
- //write GUID at the beginning of the file: this ID is a universal identifier for this lock (no matter what the path is, considering symlinks, distributed network, etc.)
- FileOutputStream lockFile(lockfilename); //throw FileError
- LockInformation().toStream(lockFile);
-}
-
-
-LockInformation retrieveLockInfo(const Zstring& lockfilename) //throw FileError, ErrorNotExisting
-{
- //read GUID from beginning of file
- FileInputStream lockFile(lockfilename); //throw FileError, ErrorNotExisting
- return LockInformation(lockFile);
-}
-
-
-std::string retrieveLockId(const Zstring& lockfilename) //throw FileError, ErrorNotExisting
-{
- return retrieveLockInfo(lockfilename).lockId;
-}
-}
-
-
-void waitOnDirLock(const Zstring& lockfilename, DirLockCallback* callback) //throw FileError
-{
- std::wstring infoMsg = _("Waiting while directory is locked (%x)...");
- replace(infoMsg, L"%x", std::wstring(L"\"") + lockfilename + "\"");
- if (callback)
- callback->reportInfo(infoMsg);
- //---------------------------------------------------------------
- try
- {
- const LockInformation lockInfo = retrieveLockInfo(lockfilename); //throw FileError, ErrorNotExisting
-
- bool lockOwnderDead = false; //convenience optimization: if we know the owning process crashed, we needn't wait DETECT_EXITUS_INTERVAL sec
- switch (getProcessStatus(lockInfo.procDescr))
- {
- case PROC_STATUS_ITS_US: //since we've already passed LockAdmin, the lock file seems abandoned ("stolen"?) although it's from this process
- case PROC_STATUS_NOT_RUNNING:
- lockOwnderDead = true;
- break;
- case PROC_STATUS_RUNNING:
- case PROC_STATUS_NO_IDEA:
- break;
- }
-
- zen::UInt64 fileSizeOld;
- wxLongLong lockSilentStart = wxGetLocalTimeMillis();
-
- while (true)
- {
- const zen::UInt64 fileSizeNew = ::getLockFileSize(lockfilename); //throw FileError, ErrorNotExisting
- wxLongLong currentTime = wxGetLocalTimeMillis();
-
- if (fileSizeNew != fileSizeOld)
- {
- //received life sign from lock
- fileSizeOld = fileSizeNew;
- lockSilentStart = currentTime;
- }
-
- if (lockOwnderDead || //no need to wait any longer...
- currentTime - lockSilentStart > DETECT_EXITUS_INTERVAL)
- {
- DirLock dummy(deleteAbandonedLockName(lockfilename), callback); //throw FileError
-
- //now that the lock is in place check existence again: meanwhile another process may have deleted and created a new lock!
-
- if (retrieveLockId(lockfilename) != lockInfo.lockId) //throw FileError, ErrorNotExisting
- return; //another process has placed a new lock, leave scope: the wait for the old lock is technically over...
-
- if (getLockFileSize(lockfilename) != fileSizeOld) //throw FileError, ErrorNotExisting
- continue; //belated lifesign
-
- removeFile(lockfilename); //throw FileError
- return;
- }
-
- //wait some time...
- const size_t GUI_CALLBACK_INTERVAL = 100;
- for (size_t i = 0; i < POLL_LIFE_SIGN_INTERVAL / GUI_CALLBACK_INTERVAL; ++i)
- {
- if (callback) callback->requestUiRefresh();
- wxMilliSleep(GUI_CALLBACK_INTERVAL);
-
- //show some countdown on abandoned locks
- if (callback)
- {
- if (currentTime - lockSilentStart > EMIT_LIFE_SIGN_INTERVAL) //one signal missed: it's likely this is an abandoned lock:
- {
- long remainingSeconds = ((DETECT_EXITUS_INTERVAL - (wxGetLocalTimeMillis() - lockSilentStart)) / 1000).ToLong();
- remainingSeconds = std::max(0L, remainingSeconds);
-
- std::wstring remSecMsg = _P("1 sec", "%x sec", remainingSeconds);
- replace(remSecMsg, L"%x", toString<std::wstring>(remainingSeconds));
- callback->reportInfo(infoMsg + " " + remSecMsg);
- }
- else
- callback->reportInfo(infoMsg); //emit a message in any case (might clear other one)
- }
- }
- }
- }
- catch (const ErrorNotExisting&)
- {
- return; //what we are waiting for...
- }
-}
-
-
-void releaseLock(const Zstring& lockfilename) //throw ()
-{
- try
- {
- removeFile(lockfilename);
- }
- catch (...) {}
-}
-
-
-bool tryLock(const Zstring& lockfilename) //throw FileError
-{
-#ifdef FFS_WIN
- const HANDLE fileHandle = ::CreateFile(applyLongPathPrefix(lockfilename).c_str(),
- GENERIC_READ | GENERIC_WRITE, //use both when writing over network, see comment in file_io.cpp
- FILE_SHARE_READ,
- 0,
- CREATE_NEW,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (fileHandle == INVALID_HANDLE_VALUE)
- {
-#ifndef _MSC_VER
-#warning fix this problem!
- //read-only FTP may return: ERROR_FILE_EXISTS (NetDrive @ GNU)
-#endif
- if (::GetLastError() == ERROR_FILE_EXISTS)
- return false;
- else
- throw FileError(_("Error setting directory lock:") + "\n\"" + lockfilename + "\"" + "\n\n" + getLastErrorFormatted());
- }
- ::CloseHandle(fileHandle);
-
-#elif defined FFS_LINUX
- //O_EXCL contains a race condition on NFS file systems: http://linux.die.net/man/2/open
- ::umask(0); //important!
- const int fileHandle = ::open(lockfilename.c_str(), O_CREAT | O_WRONLY | O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO);
- if (fileHandle == -1)
- {
- if (errno == EEXIST)
- return false;
- else
- throw FileError(_("Error setting directory lock:") + "\n\"" + lockfilename + "\"" + "\n\n" + getLastErrorFormatted());
- }
- ::close(fileHandle);
-#endif
-
- Loki::ScopeGuard guardLockFile = Loki::MakeGuard(zen::removeFile, lockfilename);
-
- //write UUID at the beginning of the file: this ID is a universal identifier for this lock (no matter what the path is, considering symlinks, etc.)
- writeLockInfo(lockfilename); //throw FileError
-
- guardLockFile.Dismiss(); //lockfile created successfully
- return true;
-}
-}
-
-
-class DirLock::SharedDirLock
-{
-public:
- SharedDirLock(const Zstring& lockfilename, DirLockCallback* callback = NULL) : //throw FileError
- lockfilename_(lockfilename)
- {
- while (!::tryLock(lockfilename)) //throw FileError
- ::waitOnDirLock(lockfilename, callback); //
-
- threadObj = boost::thread(LifeSigns(lockfilename));
- }
-
- ~SharedDirLock()
- {
- threadObj.interrupt(); //thread lifetime is subset of this instances's life
- threadObj.join();
-
- ::releaseLock(lockfilename_); //throw ()
- }
-
-private:
- SharedDirLock(const DirLock&);
- SharedDirLock& operator=(const DirLock&);
-
- const Zstring lockfilename_;
-
- boost::thread threadObj;
-};
-
-
-class DirLock::LockAdmin //administrate all locks held by this process to avoid deadlock by recursion
-{
-public:
- static LockAdmin& instance()
- {
- static LockAdmin inst;
- return inst;
- }
-
- //create or retrieve a SharedDirLock
- std::shared_ptr<SharedDirLock> retrieve(const Zstring& lockfilename, DirLockCallback* callback) //throw FileError
- {
- //optimization: check if there is an active(!) lock for "lockfilename"
- FileToUuidMap::const_iterator iterUuid = fileToUuid.find(lockfilename);
- if (iterUuid != fileToUuid.end())
- {
- const std::shared_ptr<SharedDirLock>& activeLock = findActive(iterUuid->second); //returns null-lock if not found
- if (activeLock)
- return activeLock; //SharedDirLock is still active -> enlarge circle of shared ownership
- }
-
- try //actual check based on lock UUID, deadlock prevention: "lockfilename" may be an alternative name for an already active lock
- {
- const std::string lockId = retrieveLockId(lockfilename); //throw FileError, ErrorNotExisting
-
- const std::shared_ptr<SharedDirLock>& activeLock = findActive(lockId); //returns null-lock if not found
- if (activeLock)
- {
- fileToUuid[lockfilename] = lockId; //perf-optimization: update relation
- return activeLock;
- }
- }
- catch (...) {} //catch everything, let SharedDirLock constructor deal with errors, e.g. 0-sized/corrupted lock file
-
- //not yet in buffer, so create a new directory lock
- std::shared_ptr<SharedDirLock> newLock(new SharedDirLock(lockfilename, callback)); //throw FileError
- const std::string newLockId = retrieveLockId(lockfilename); //throw FileError, ErrorNotExisting
-
- //update registry
- fileToUuid[lockfilename] = newLockId; //throw()
- uuidToLock[newLockId] = newLock; //
-
- return newLock;
- }
-
-private:
- LockAdmin() {}
-
- std::shared_ptr<SharedDirLock> findActive(const std::string& lockId) //returns null-lock if not found
- {
- UuidToLockMap::const_iterator iterLock = uuidToLock.find(lockId);
- return iterLock != uuidToLock.end() ?
- iterLock->second.lock() : //try to get shared_ptr; throw()
- std::shared_ptr<SharedDirLock>();
- }
-
- typedef std::weak_ptr<SharedDirLock> SharedLock;
-
- typedef std::string UniqueId;
- typedef std::map<Zstring, UniqueId, LessFilename> FileToUuidMap; //n:1 handle uppper/lower case correctly
- typedef std::map<UniqueId, SharedLock> UuidToLockMap; //1:1
-
- FileToUuidMap fileToUuid; //lockname |-> UUID; locks can be referenced by a lockfilename or alternatively a UUID
- UuidToLockMap uuidToLock; //UUID |-> "shared lock ownership"
-};
-
-
-DirLock::DirLock(const Zstring& lockfilename, DirLockCallback* callback) //throw FileError
-{
-#ifdef FFS_WIN
- std::vector<wchar_t> volName(std::max(lockfilename.size(), static_cast<size_t>(10000)));
- if (::GetVolumePathName(lockfilename.c_str(), //__in LPCTSTR lpszFileName,
- &volName[0], //__out LPTSTR lpszVolumePathName,
- static_cast<DWORD>(volName.size()))) //__in DWORD cchBufferLength
- {
- DWORD dt = ::GetDriveType(&volName[0]);
- if (dt == DRIVE_CDROM)
- return; //we don't need a lock for a CD ROM
- }
-#endif
-
- sharedLock = LockAdmin::instance().retrieve(lockfilename, callback);
-}
diff --git a/library/dir_lock.h b/library/dir_lock.h
deleted file mode 100644
index 8cec9d69..00000000
--- a/library/dir_lock.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef DIR_LOCK_H_INCLUDED
-#define DIR_LOCK_H_INCLUDED
-
-#include "../shared/file_error.h"
-#include <memory>
-
-
-struct DirLockCallback //while waiting for the lock
-{
- virtual ~DirLockCallback() {}
- virtual void requestUiRefresh() = 0; //allowed to throw exceptions
- virtual void reportInfo(const std::wstring& text) = 0;
-};
-
-/*
-RAII structure to place a directory lock against other FFS processes:
- - recursive locking supported, even with alternate lockfile names, e.g. via symlinks, network mounts etc.
- - ownership shared between all object instances refering to a specific lock location(= UUID)
- - can be copied safely and efficiently! (ref-counting)
- - detects and resolves abandoned locks (instantly if lock is associated with local pc, else after 30 seconds)
- - temporary locks created during abandoned lock resolution keep "lockfilename"'s extension
- - race-free (Windows, almost on Linux(NFS))
-*/
-class DirLock
-{
-public:
- DirLock(const Zstring& lockfilename, DirLockCallback* callback = NULL); //throw FileError, callback only used during construction
-
-private:
- class LockAdmin;
- class SharedDirLock;
- std::shared_ptr<SharedDirLock> sharedLock;
-};
-
-#endif // DIR_LOCK_H_INCLUDED
diff --git a/library/error_log.cpp b/library/error_log.cpp
deleted file mode 100644
index 28819f40..00000000
--- a/library/error_log.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#include "error_log.h"
-#include <wx/datetime.h>
-#include "../shared/i18n.h"
-
-
-using zen::ErrorLogging;
-
-
-void ErrorLogging::logMsg(const wxString& message, zen::MessageType type)
-{
- Entry newEntry;
- newEntry.type = type;
- newEntry.time = wxDateTime::GetTimeNow();
- newEntry.message = message;
-
- messages.push_back(newEntry);
-
- ++statistics[type];
-}
-
-
-int ErrorLogging::typeCount(int types) const
-{
- int count = 0;
-
- if (types & TYPE_INFO)
- count += statistics[TYPE_INFO];
- if (types & TYPE_WARNING)
- count += statistics[TYPE_WARNING];
- if (types & TYPE_ERROR)
- count += statistics[TYPE_ERROR];
- if (types & TYPE_FATAL_ERROR)
- count += statistics[TYPE_FATAL_ERROR];
-
- return count;
-}
-
-
-std::vector<wxString> ErrorLogging::getFormattedMessages(int types) const
-{
- std::vector<wxString> output;
-
- for (std::vector<Entry>::const_iterator i = messages.begin(); i != messages.end(); ++i)
- if (i->type & types)
- output.push_back(formatMessage(*i));
-
- return output;
-}
-
-
-wxString ErrorLogging::formatMessage(const Entry& msg)
-{
- wxString typeName;
- switch (msg.type)
- {
- case TYPE_INFO:
- typeName = _("Info");
- break;
- case TYPE_WARNING:
- typeName = _("Warning");
- break;
- case TYPE_ERROR:
- typeName = _("Error");
- break;
- case TYPE_FATAL_ERROR:
- typeName = _("Fatal Error");
- break;
- }
-
- const wxString prefix = wxString(L"[") + wxDateTime(msg.time).FormatTime() + L"] " + typeName + L": ";
-
- wxString formattedText = prefix;
- for (auto i = msg.message.begin(); i != msg.message.end(); ++i)
- if (*i == wxChar('\n'))
- {
- formattedText += L'\n';
-
- wxString blanks;
- blanks.resize(prefix.size(), L' ');
- formattedText += blanks;
-
- while (*++i == L'\n') //remove duplicate newlines
- ;
- --i;
- }
- else
- formattedText += *i;
-
- return formattedText;
-}
diff --git a/library/error_log.h b/library/error_log.h
deleted file mode 100644
index f8a0c909..00000000
--- a/library/error_log.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#ifndef ERRORLOGGING_H_INCLUDED
-#define ERRORLOGGING_H_INCLUDED
-
-#include <wx/string.h>
-#include <vector>
-#include <map>
-
-
-namespace zen
-{
-enum MessageType
-{
- TYPE_INFO = 1,
- TYPE_WARNING = 2,
- TYPE_ERROR = 4,
- TYPE_FATAL_ERROR = 8,
-};
-
-class ErrorLogging
-{
-public:
- void logMsg(const wxString& message, MessageType type);
-
- int typeCount(int types = TYPE_INFO | TYPE_WARNING | TYPE_ERROR | TYPE_FATAL_ERROR) const;
-
- std::vector<wxString> getFormattedMessages(int types = TYPE_INFO | TYPE_WARNING | TYPE_ERROR | TYPE_FATAL_ERROR) const;
-
-private:
- struct Entry
- {
- MessageType type;
- time_t time;
- wxString message;
- };
-
- static wxString formatMessage(const Entry& msg);
-
- std::vector<Entry> messages; //list of non-resolved errors and warnings
-
- mutable std::map<MessageType, int> statistics;
-};
-}
-
-#endif // ERRORLOGGING_H_INCLUDED
diff --git a/library/hard_filter.cpp b/library/hard_filter.cpp
deleted file mode 100644
index 56fb091b..00000000
--- a/library/hard_filter.cpp
+++ /dev/null
@@ -1,368 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#include "hard_filter.h"
-#include "../shared/zstring.h"
-#include <wx/string.h>
-#include <set>
-#include <stdexcept>
-#include <vector>
-#include "../structures.h"
-#include <boost/bind.hpp>
-#include "../shared/loki/LokiTypeInfo.h"
-#include "../shared/serialize.h"
-
-using namespace zen;
-
-
-//--------------------------------------------------------------------------------------------------
-bool zen::operator<(const HardFilter& lhs, const HardFilter& rhs)
-{
- if (Loki::TypeInfo(typeid(lhs)) != typeid(rhs))
- return Loki::TypeInfo(typeid(lhs)) < typeid(rhs);
-
- //this and other are same type:
- return lhs.cmpLessSameType(rhs);
-}
-
-
-void HardFilter::saveFilter(wxOutputStream& stream) const //serialize derived object
-{
- //save type information
- writeString(stream, uniqueClassIdentifier());
-
- //save actual object
- save(stream);
-}
-
-
-HardFilter::FilterRef HardFilter::loadFilter(wxInputStream& stream)
-{
- //read type information
- const Zstring uniqueClassId = readString<Zstring>(stream);
-
- //read actual object
- if (uniqueClassId == Zstr("NullFilter"))
- return NullFilter::load(stream);
- else if (uniqueClassId == Zstr("NameFilter"))
- return NameFilter::load(stream);
- else if (uniqueClassId == Zstr("CombinedFilter"))
- return CombinedFilter::load(stream);
- else
- throw std::logic_error("Programming Error: Unknown filter!");
-}
-
-
-//--------------------------------------------------------------------------------------------------
-void addFilterEntry(const Zstring& filtername, std::set<Zstring>& fileFilter, std::set<Zstring>& directoryFilter)
-{
- Zstring filterFormatted = filtername;
-
-#ifdef FFS_WIN
- //Windows does NOT distinguish between upper/lower-case
- makeUpper(filterFormatted);
-#elif defined FFS_LINUX
- //Linux DOES distinguish between upper/lower-case: nothing to do here
-#endif
-
- const Zstring sepAsterisk = Zstring(FILE_NAME_SEPARATOR) + Zchar('*');
- const Zstring sepQuestionMark = Zstring(FILE_NAME_SEPARATOR) + Zchar('?');
- const Zstring asteriskSep = Zstring(Zstr('*')) + FILE_NAME_SEPARATOR;
- const Zstring questionMarkSep = Zstring(Zstr('?')) + FILE_NAME_SEPARATOR;
-
- //--------------------------------------------------------------------------------------------------
- //add some syntactic sugar: handle beginning of filtername
- if (filterFormatted.StartsWith(FILE_NAME_SEPARATOR))
- {
- //remove leading separators (keep BEFORE test for Zstring::empty()!)
- filterFormatted = filterFormatted.AfterFirst(FILE_NAME_SEPARATOR);
- }
- else if (filterFormatted.StartsWith(asteriskSep) || // *\abc
- filterFormatted.StartsWith(questionMarkSep)) // ?\abc
- {
- addFilterEntry(Zstring(filterFormatted.c_str() + 1), fileFilter, directoryFilter); //prevent further recursion by prefix
- }
-
- //--------------------------------------------------------------------------------------------------
- //even more syntactic sugar: handle end of filtername
- if (filterFormatted.EndsWith(FILE_NAME_SEPARATOR))
- {
- const Zstring candidate = filterFormatted.BeforeLast(FILE_NAME_SEPARATOR);
- if (!candidate.empty())
- directoryFilter.insert(candidate); //only relevant for directory filtering
- }
- else if (filterFormatted.EndsWith(sepAsterisk) || // abc\*
- filterFormatted.EndsWith(sepQuestionMark)) // abc\?
- {
- fileFilter.insert( filterFormatted);
- directoryFilter.insert(filterFormatted);
-
- const Zstring candidate = filterFormatted.BeforeLast(FILE_NAME_SEPARATOR);
- if (!candidate.empty())
- directoryFilter.insert(candidate); //only relevant for directory filtering
- }
- else if (!filterFormatted.empty())
- {
- fileFilter. insert(filterFormatted);
- directoryFilter.insert(filterFormatted);
- }
-}
-
-
-namespace
-{
-template <class T>
-inline
-const T* cStringFind(const T* str1, T ch) //strchr()
-{
- while (*str1 != ch) //ch is allowed to be 0 by contract! must return end of string in this case
- {
- if (*str1 == 0)
- return NULL;
- ++str1;
- }
- return str1;
-}
-
-bool matchesMask(const Zchar* str, const Zchar* mask)
-{
- for (Zchar ch; (ch = *mask) != 0; ++mask, ++str)
- {
- switch (ch)
- {
- case Zstr('?'):
- if (*str == 0)
- return false;
- break;
-
- case Zstr('*'):
- //advance to next non-*/? char
- do
- {
- ++mask;
- ch = *mask;
- }
- while (ch == Zstr('*') || ch == Zstr('?'));
- //if mask ends with '*':
- if (ch == 0)
- return true;
-
- ++mask;
- while ((str = cStringFind(str, ch)) != NULL)
- {
- ++str;
- if (matchesMask(str, mask))
- return true;
- }
- return false;
-
- default:
- if (*str != ch)
- return false;
- }
- }
- return *str == 0;
-}
-
-//returns true if string matches at least the beginning of mask
-inline
-bool matchesMaskBegin(const Zchar* str, const Zchar* mask)
-{
- for (Zchar ch; (ch = *mask) != 0; ++mask, ++str)
- {
- if (*str == 0)
- return true;
-
- switch (ch)
- {
- case Zstr('?'):
- break;
-
- case Zstr('*'):
- return true;
-
- default:
- if (*str != ch)
- return false;
- }
- }
- return *str == 0;
-}
-}
-
-
-class MatchFound : public std::unary_function<Zstring, bool>
-{
-public:
- MatchFound(const Zstring& name) : name_(name) {}
-
- bool operator()(const Zstring& mask) const
- {
- return matchesMask(name_.c_str(), mask.c_str());
- }
-private:
- const Zstring& name_;
-};
-
-
-inline
-bool matchesFilter(const Zstring& nameFormatted, const std::set<Zstring>& filter)
-{
- return std::find_if(filter.begin(), filter.end(), MatchFound(nameFormatted)) != filter.end();
-}
-
-
-inline
-bool matchesFilterBegin(const Zstring& nameFormatted, const std::set<Zstring>& filter)
-{
- for (std::set<Zstring>::const_iterator i = filter.begin(); i != filter.end(); ++i)
- if (matchesMaskBegin(nameFormatted.c_str(), i->c_str()))
- return true;
- return false;
-
- // return std::find_if(filter.begin(), filter.end(),
- // boost::bind(matchesMaskBegin, nameFormatted.c_str(), _1)) != filter.end();
-}
-
-
-std::vector<Zstring> compoundStringToFilter(const Zstring& filterString)
-{
- //delimiters may be ';' or '\n'
- std::vector<Zstring> output;
-
- const std::vector<Zstring> blocks = split(filterString, Zchar(';'));
- std::for_each(blocks.begin(), blocks.end(),
- [&](const Zstring& item)
- {
- const std::vector<Zstring> blocks2 = split(item, Zchar('\n'));
-
- std::for_each(blocks2.begin(), blocks2.end(),
- [&](Zstring entry)
- {
- trim(entry);
- if (!entry.empty())
- output.push_back(entry);
- });
- });
-
- return output;
-}
-
-//#################################################################################################
-NameFilter::NameFilter(const Zstring& includeFilter, const Zstring& excludeFilter) :
- includeFilterTmp(includeFilter), //save constructor arguments for serialization
- excludeFilterTmp(excludeFilter)
-{
- //no need for regular expressions! In tests wxRegex was by factor of 10 slower than wxString::Matches()!!
-
- //load filter into vectors of strings
- //delimiters may be ';' or '\n'
- const std::vector<Zstring>& includeList = compoundStringToFilter(includeFilter);
- const std::vector<Zstring>& excludeList = compoundStringToFilter(excludeFilter);
-
- //setup include/exclude filters for files and directories
- std::for_each(includeList.begin(), includeList.end(), [&](const Zstring& entry) { addFilterEntry(entry, filterFileIn, filterFolderIn); });
- std::for_each(excludeList.begin(), excludeList.end(), [&](const Zstring& entry) { addFilterEntry(entry, filterFileEx, filterFolderEx); });
-}
-
-
-bool NameFilter::passFileFilter(const Zstring& relFilename) const
-{
-#ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case
- Zstring nameFormatted = relFilename;
- makeUpper(nameFormatted);
-#elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case
- const Zstring& nameFormatted = relFilename; //nothing to do here
-#endif
-
- return matchesFilter(nameFormatted, filterFileIn) && //process include filters
- !matchesFilter(nameFormatted, filterFileEx); //process exclude filters
-}
-
-
-bool NameFilter::passDirFilter(const Zstring& relDirname, bool* subObjMightMatch) const
-{
- assert(subObjMightMatch == NULL || *subObjMightMatch == true); //check correct usage
-
-#ifdef FFS_WIN //Windows does NOT distinguish between upper/lower-case
- Zstring nameFormatted = relDirname;
- makeUpper(nameFormatted);
-#elif defined FFS_LINUX //Linux DOES distinguish between upper/lower-case
- const Zstring& nameFormatted = relDirname; //nothing to do here
-#endif
-
- if (matchesFilter(nameFormatted, filterFolderEx)) //process exclude filters
- {
- if (subObjMightMatch)
- *subObjMightMatch = false; //exclude subfolders/subfiles as well
- return false;
- }
-
- if (!matchesFilter(nameFormatted, filterFolderIn)) //process include filters
- {
- if (subObjMightMatch)
- {
- const Zstring& subNameBegin = nameFormatted + FILE_NAME_SEPARATOR; //const-ref optimization
-
- *subObjMightMatch = matchesFilterBegin(subNameBegin, filterFileIn) || //might match a file in subdirectory
- matchesFilterBegin(subNameBegin, filterFolderIn); //or another subdirectory
- }
- return false;
- }
-
- return true;
-}
-
-
-bool NameFilter::isNull() const
-{
- static NameFilter output(Zstr("*"), Zstring());
- return *this == output;
-}
-
-
-bool NameFilter::cmpLessSameType(const HardFilter& other) const
-{
- assert(typeid(*this) == typeid(other)); //always given in this context!
-
- const NameFilter& otherNameFilt = static_cast<const NameFilter&>(other);
-
- if (filterFileIn != otherNameFilt.filterFileIn)
- return filterFileIn < otherNameFilt.filterFileIn;
-
- if (filterFolderIn != otherNameFilt.filterFolderIn)
- return filterFolderIn < otherNameFilt.filterFolderIn;
-
- if (filterFileEx != otherNameFilt.filterFileEx)
- return filterFileEx < otherNameFilt.filterFileEx;
-
- if (filterFolderEx != otherNameFilt.filterFolderEx)
- return filterFolderEx < otherNameFilt.filterFolderEx;
-
- return false; //vectors equal
-}
-
-
-Zstring NameFilter::uniqueClassIdentifier() const
-{
- return Zstr("NameFilter");
-}
-
-
-void NameFilter::save(wxOutputStream& stream) const
-{
- writeString(stream, includeFilterTmp);
- writeString(stream, excludeFilterTmp);
-}
-
-
-HardFilter::FilterRef NameFilter::load(wxInputStream& stream) //"constructor"
-{
- const Zstring include = readString<Zstring>(stream);
- const Zstring exclude = readString<Zstring>(stream);
-
- return FilterRef(new NameFilter(include, exclude));
-}
diff --git a/library/hard_filter.h b/library/hard_filter.h
deleted file mode 100644
index bb0b6d54..00000000
--- a/library/hard_filter.h
+++ /dev/null
@@ -1,279 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#ifndef FFS_FILTER_H_INCLUDED
-#define FFS_FILTER_H_INCLUDED
-
-#include "../shared/zstring.h"
-#include <set>
-#include <memory>
-#include <wx/stream.h>
-
-namespace zen
-{
-//------------------------------------------------------------------
-/*
-Semantics of HardFilter:
-1. using it creates a NEW folder hierarchy! -> must be considered by <Automatic>-mode! (fortunately it turns out, doing nothing already has perfect semantics :)
-2. it applies equally to both sides => it always matches either both sides or none! => can be used while traversing a single folder!
-
- class hierarchy:
-
- HardFilter (interface)
- /|\
- _________|_____________
- | | |
-NullFilter NameFilter CombinedFilter
-*/
-
-class HardFilter //interface for filtering
-{
-public:
- virtual ~HardFilter() {}
-
- //filtering
- virtual bool passFileFilter(const Zstring& relFilename) const = 0;
- virtual bool passDirFilter (const Zstring& relDirname, bool* subObjMightMatch) const = 0;
- //subObjMightMatch: file/dir in subdirectories could(!) match
- //note: variable is only set if passDirFilter returns false!
-
- virtual bool isNull() const = 0; //filter is equivalent to NullFilter, but may be technically slower
-
- typedef std::shared_ptr<const HardFilter> FilterRef; //always bound by design!
-
- //serialization
- void saveFilter(wxOutputStream& stream) const; //serialize derived object
- static FilterRef loadFilter(wxInputStream& stream); //CAVEAT!!! adapt this method for each new derivation!!!
-
-private:
- friend bool operator< (const HardFilter& lhs, const HardFilter& rhs);
-
- virtual void save(wxOutputStream& stream) const = 0; //serialization
- virtual Zstring uniqueClassIdentifier() const = 0; //get identifier, used for serialization
- virtual bool cmpLessSameType(const HardFilter& other) const = 0; //typeid(*this) == typeid(other) in this context!
-};
-
-inline bool operator==(const HardFilter& lhs, const HardFilter& rhs) { return !(lhs < rhs) && !(rhs < lhs); }
-inline bool operator!=(const HardFilter& lhs, const HardFilter& rhs) { return !(lhs == rhs); }
-
-
-//small helper method: merge two hard filters (thereby remove Null-filters)
-HardFilter::FilterRef combineFilters(const HardFilter::FilterRef& first,
- const HardFilter::FilterRef& second);
-
-
-class NullFilter : public HardFilter //no filtering at all
-{
-public:
- virtual bool passFileFilter(const Zstring& relFilename) const;
- virtual bool passDirFilter(const Zstring& relDirname, bool* subObjMightMatch) const;
- virtual bool isNull() const;
-
-private:
- friend class HardFilter;
- virtual void save(wxOutputStream& stream) const {}
- virtual Zstring uniqueClassIdentifier() const;
- static FilterRef load(wxInputStream& stream); //"serial constructor"
- virtual bool cmpLessSameType(const HardFilter& other) const;
-};
-
-
-class NameFilter : public HardFilter //standard filter by filename
-{
-public:
- NameFilter(const Zstring& includeFilter, const Zstring& excludeFilter);
-
- virtual bool passFileFilter(const Zstring& relFilename) const;
- virtual bool passDirFilter(const Zstring& relDirname, bool* subObjMightMatch) const;
- virtual bool isNull() const;
-
-private:
- friend class HardFilter;
- virtual void save(wxOutputStream& stream) const;
- virtual Zstring uniqueClassIdentifier() const;
- static FilterRef load(wxInputStream& stream); //"serial constructor"
- virtual bool cmpLessSameType(const HardFilter& other) const;
-
- std::set<Zstring> filterFileIn; //upper case (windows)
- std::set<Zstring> filterFolderIn; //
- std::set<Zstring> filterFileEx; //
- std::set<Zstring> filterFolderEx; //
-
- const Zstring includeFilterTmp; //save constructor arguments for serialization
- const Zstring excludeFilterTmp; //
-};
-
-
-class CombinedFilter : public HardFilter //combine two filters to match if and only if both match
-{
-public:
- CombinedFilter(const FilterRef& first, const FilterRef& second) : first_(first), second_(second) {}
-
- virtual bool passFileFilter(const Zstring& relFilename) const;
- virtual bool passDirFilter(const Zstring& relDirname, bool* subObjMightMatch) const;
- virtual bool isNull() const;
-
-private:
- friend class HardFilter;
- virtual void save(wxOutputStream& stream) const;
- virtual Zstring uniqueClassIdentifier() const;
- static FilterRef load(wxInputStream& stream); //"serial constructor"
- virtual bool cmpLessSameType(const HardFilter& other) const;
-
- const FilterRef first_;
- const FilterRef second_;
-};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-//---------------Inline Implementation---------------------------------------------------
-inline
-HardFilter::FilterRef NullFilter::load(wxInputStream& stream) //"serial constructor"
-{
- return FilterRef(new NullFilter);
-}
-
-
-inline
-bool NullFilter::passFileFilter(const Zstring& relFilename) const
-{
- return true;
-}
-
-
-inline
-bool NullFilter::passDirFilter(const Zstring& relDirname, bool* subObjMightMatch) const
-{
- assert(subObjMightMatch == NULL || *subObjMightMatch == true); //check correct usage
- return true;
-}
-
-
-inline
-bool NullFilter::isNull() const
-{
- return true;
-}
-
-
-inline
-bool NullFilter::cmpLessSameType(const HardFilter& other) const
-{
- assert(typeid(*this) == typeid(other)); //always given in this context!
- return false;
-}
-
-
-inline
-Zstring NullFilter::uniqueClassIdentifier() const
-{
- return Zstr("NullFilter");
-}
-
-
-inline
-bool CombinedFilter::passFileFilter(const Zstring& relFilename) const
-{
- return first_->passFileFilter(relFilename) && //short-circuit behavior
- second_->passFileFilter(relFilename);
-}
-
-
-inline
-bool CombinedFilter::passDirFilter(const Zstring& relDirname, bool* subObjMightMatch) const
-{
- return first_->passDirFilter(relDirname, subObjMightMatch) && //short-circuit behavior: subObjMightMatch handled correctly!
- second_->passDirFilter(relDirname, subObjMightMatch);
-}
-
-
-inline
-bool CombinedFilter::isNull() const
-{
- return first_->isNull() && second_->isNull();
-}
-
-
-inline
-bool CombinedFilter::cmpLessSameType(const HardFilter& other) const
-{
- assert(typeid(*this) == typeid(other)); //always given in this context!
-
- const CombinedFilter& otherCombFilt = static_cast<const CombinedFilter&>(other);
-
- if (*first_ != *otherCombFilt.first_)
- return *first_ < *otherCombFilt.first_;
-
- return *second_ < *otherCombFilt.second_;
-}
-
-
-inline
-Zstring CombinedFilter::uniqueClassIdentifier() const
-{
- return Zstr("CombinedFilter");
-}
-
-
-inline
-void CombinedFilter::save(wxOutputStream& stream) const
-{
- first_->saveFilter(stream);
- second_->saveFilter(stream);
-}
-
-
-inline
-HardFilter::FilterRef CombinedFilter::load(wxInputStream& stream) //"constructor"
-{
- FilterRef first = loadFilter(stream);
- FilterRef second = loadFilter(stream);
-
- return combineFilters(first, second);
-}
-
-
-inline
-HardFilter::FilterRef combineFilters(const HardFilter::FilterRef& first,
- const HardFilter::FilterRef& second)
-{
- if (first->isNull())
- {
- if (second->isNull())
- return HardFilter::FilterRef(new NullFilter);
- else
- return second;
- }
- else
- {
- if (second->isNull())
- return first;
- else
- return HardFilter::FilterRef(new CombinedFilter(first, second));
- }
-}
-
-
-}
-
-
-#endif // FFS_FILTER_H_INCLUDED
-
diff --git a/library/icon_buffer.cpp b/library/icon_buffer.cpp
deleted file mode 100644
index b8ee66cd..00000000
--- a/library/icon_buffer.cpp
+++ /dev/null
@@ -1,613 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#include "icon_buffer.h"
-#include <queue>
-#include <set>
-#include "../shared/boost_thread_wrap.h" //include <boost/thread.hpp>
-#include "../shared/loki/ScopeGuard.h"
-#include <boost/thread/once.hpp>
-
-#ifdef FFS_WIN
-#include <wx/msw/wrapwin.h> //includes "windows.h"
-#include "../shared/dll_loader.h"
-#include "../shared/Thumbnail/thumbnail.h"
-
-#elif defined FFS_LINUX
-#include <giomm/file.h>
-#include <gtkmm/icontheme.h>
-#include <gtkmm/main.h>
-#endif
-
-using namespace zen;
-
-
-const size_t BUFFER_SIZE_MAX = 800; //maximum number of icons to buffer
-
-
-int zen::IconBuffer::cvrtSize(IconSize sz) //get size in pixel
-{
- switch (sz)
- {
- case SIZE_SMALL:
-#ifdef FFS_WIN
- return 16;
-#elif defined FFS_LINUX
- return 24;
-#endif
- case SIZE_MEDIUM:
- return 48;
- case SIZE_LARGE:
- return 128;
- }
- assert(false);
- return 0;
-}
-
-
-class IconHolder //handle HICON/GdkPixbuf ownership WITHOUT ref-counting to allow thread-safe usage (in contrast to wxIcon)
-{
-public:
-#ifdef FFS_WIN
- typedef HICON HandleType;
-#elif defined FFS_LINUX
- typedef GdkPixbuf* HandleType;
-#endif
-
- IconHolder(HandleType handle = 0) : handle_(handle) {} //take ownership!
-
- //icon holder has value semantics!
- IconHolder(const IconHolder& other) : handle_(other.handle_ == NULL ? NULL :
-#ifdef FFS_WIN
- ::CopyIcon(other.handle_)
-#elif defined FFS_LINUX
- ::gdk_pixbuf_copy(other.handle_) //create new Pix buf with reference count 1 or return 0 on error
-#endif
- ) {}
-
- IconHolder& operator=(const IconHolder& other)
- {
- IconHolder(other).swap(*this);
- return *this;
- }
-
- ~IconHolder()
- {
- if (handle_ != NULL)
-#ifdef FFS_WIN
- ::DestroyIcon(handle_);
-#elif defined FFS_LINUX
- ::g_object_unref(handle_);
-#endif
- }
-
- void swap(IconHolder& other) { std::swap(handle_, other.handle_); } //throw()
-
- wxIcon toWxIcon(int expectedSize) const //copy HandleType, caller needs to take ownership!
- {
- if (handle_ == NULL)
- return wxNullIcon;
-
- IconHolder clone(*this);
-
- wxIcon newIcon; //attention: wxIcon uses reference counting!
-#ifdef FFS_WIN
- newIcon.SetHICON(clone.handle_);
-
- { //this block costs ~0.04 ms
- ICONINFO icoInfo = {};
- if (::GetIconInfo(clone.handle_, &icoInfo))
- {
- ::DeleteObject(icoInfo.hbmMask); //nice potential for a GDI leak!
- LOKI_ON_BLOCK_EXIT2(::DeleteObject(icoInfo.hbmColor)); //
-
- BITMAP bmpInfo = {};
- if (::GetObject(icoInfo.hbmColor, //__in HGDIOBJ hgdiobj,
- sizeof(BITMAP), //__in int cbBuffer,
- &bmpInfo) != 0) // __out LPVOID lpvObject
- {
- const int maxExtent = std::max(bmpInfo.bmWidth, bmpInfo.bmHeight);
- if (maxExtent > expectedSize)
- {
- bmpInfo.bmWidth = bmpInfo.bmWidth * expectedSize / maxExtent; //scale those Vista jumbo 256x256 icons down!
- bmpInfo.bmHeight = bmpInfo.bmHeight * expectedSize / maxExtent; //
- }
- newIcon.SetSize(bmpInfo.bmWidth, bmpInfo.bmHeight); //wxIcon is stretched to this size
- }
- }
- }
- //no stretching for now
- //newIcon.SetSize(defaultSize, defaultSize); //icon is stretched to this size if referenced HICON differs
-
-#elif defined FFS_LINUX //
- newIcon.SetPixbuf(clone.handle_); // transfer ownership!!
-#endif //
- clone.handle_ = NULL; //
- return newIcon;
- }
-
-private:
- HandleType handle_;
- struct ConversionToBool { int dummy; };
-
-public:
- //use member pointer as implicit conversion to bool (C++ Templates - Vandevoorde/Josuttis; chapter 20)
- operator int ConversionToBool::* () const { return handle_ != NULL ? &ConversionToBool::dummy : NULL; }
-};
-
-
-#ifdef FFS_WIN
-namespace
-{
-Zstring getFileExtension(const Zstring& filename)
-{
- const Zstring shortName = afterLast(filename, Zchar('\\')); //warning: using windows file name separator!
-
- return shortName.find(Zchar('.')) != Zstring::npos ?
- filename.AfterLast(Zchar('.')) :
- Zstring();
-}
-
-std::set<Zstring, LessFilename> priceyExtensions; //thread-safe!
-boost::once_flag initExtensionsOnce = BOOST_ONCE_INIT; //
-
-
-//test for extension for non-thumbnail icons that physically have to be retrieved from disc
-bool isCheapExtension(const Zstring& extension)
-{
- boost::call_once(initExtensionsOnce, []()
- {
- priceyExtensions.insert(L"exe");
- priceyExtensions.insert(L"lnk");
- priceyExtensions.insert(L"ico");
- priceyExtensions.insert(L"ani");
- priceyExtensions.insert(L"cur");
- priceyExtensions.insert(L"url");
- priceyExtensions.insert(L"msc");
- priceyExtensions.insert(L"scr");
- });
- return priceyExtensions.find(extension) == priceyExtensions.end();
-}
-
-
-bool vistaOrLater()
-{
- OSVERSIONINFO osvi = {};
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-
- //IFileOperation is supported with Vista and later
- if (::GetVersionEx(&osvi))
- return osvi.dwMajorVersion > 5;
- //XP has majorVersion == 5, minorVersion == 1
- //Vista has majorVersion == 6, minorVersion == 0
- //version overview: http://msdn.microsoft.com/en-us/library/ms724834(VS.85).aspx
- return false;
-}
-
-
-bool wereVistaOrLater = false;
-boost::once_flag initVistaFlagOnce = BOOST_ONCE_INIT;
-
-
-int getShilIconType(IconBuffer::IconSize sz)
-{
- boost::call_once(initVistaFlagOnce, []()
- {
- wereVistaOrLater = vistaOrLater();
- });
-
- switch (sz)
- {
- case IconBuffer::SIZE_SMALL:
- return SHIL_SMALL; //16x16, but the size can be customized by the user.
- case IconBuffer::SIZE_MEDIUM:
- return SHIL_EXTRALARGE; //typically 48x48, but the size can be customized by the user.
- case IconBuffer::SIZE_LARGE:
- return wereVistaOrLater ? SHIL_JUMBO //normally 256x256 pixels -> will be scaled down by IconHolder
- : SHIL_EXTRALARGE; //XP doesn't have jumbo icons
- }
- return SHIL_SMALL;
-}
-
-
-util::DllFun<thumb::GetIconByIndexFct> getIconByIndex;
-boost::once_flag initGetIconByIndexOnce = BOOST_ONCE_INIT;
-
-
-IconHolder getIconByAttribute(LPCWSTR pszPath, DWORD dwFileAttributes, IconBuffer::IconSize sz)
-{
- //NOTE: CoInitializeEx()/CoUninitialize() needs to be called for THIS thread!
- SHFILEINFO fileInfo = {}; //initialize hIcon
- DWORD_PTR imgList = ::SHGetFileInfo(pszPath, //Windows 7 doesn't like this parameter to be an empty string
- dwFileAttributes,
- &fileInfo,
- sizeof(fileInfo),
- SHGFI_SYSICONINDEX | SHGFI_USEFILEATTRIBUTES);
- //no need to IUnknown::Release() imgList!
- if (!imgList)
- return NULL;
-
- boost::call_once(initGetIconByIndexOnce, []() //thread-safe init
- {
- getIconByIndex = util::DllFun<thumb::GetIconByIndexFct>(thumb::getDllName(), thumb::getIconByIndexFctName);
- });
- return getIconByIndex ? static_cast<HICON>(getIconByIndex(fileInfo.iIcon, getShilIconType(sz))) : NULL;
-}
-
-
-IconHolder getAssociatedIconByExt(const Zstring& extension, IconBuffer::IconSize sz)
-{
- //no read-access to disk! determine icon by extension
- return getIconByAttribute((Zstr("dummy.") + extension).c_str(), FILE_ATTRIBUTE_NORMAL, sz);
-}
-
-
-util::DllFun<thumb::GetThumbnailFct> getThumbnailIcon;
-boost::once_flag initThumbnailOnce = BOOST_ONCE_INIT;
-}
-#endif
-//################################################################################################################################################
-
-
-IconHolder getThumbnail(const Zstring& filename, int requestedSize) //return 0 on failure
-{
-#ifdef FFS_WIN
- using namespace thumb;
-
- boost::call_once(initThumbnailOnce, []() //note: "getThumbnail" function itself is already thread-safe
- {
- getThumbnailIcon = util::DllFun<GetThumbnailFct>(getDllName(), getThumbnailFctName);
- });
- return getThumbnailIcon ? static_cast< ::HICON>(getThumbnailIcon(filename.c_str(), requestedSize)) : NULL;
-
-#elif defined FFS_LINUX
- //call Gtk::Main::init_gtkmm_internals() on application startup!!
- try
- {
- Glib::RefPtr<Gdk::Pixbuf> iconPixbuf = Gdk::Pixbuf::create_from_file(filename.c_str(), requestedSize, requestedSize);
- if (iconPixbuf)
- return IconHolder(iconPixbuf->gobj_copy()); //copy and pass icon ownership (may be 0)
- }
- catch (const Glib::Error&) {}
-
- return IconHolder();
-#endif
-}
-
-
-IconHolder getAssociatedIcon(const Zstring& filename, IconBuffer::IconSize sz)
-{
- //1. try to load thumbnails
- switch (sz)
- {
- case IconBuffer::SIZE_SMALL:
- break;
- case IconBuffer::SIZE_MEDIUM:
- case IconBuffer::SIZE_LARGE:
- {
- IconHolder ico = getThumbnail(filename, IconBuffer::cvrtSize(sz));
- if (ico)
- return ico;
- //else: fallback to non-thumbnail icon
- }
- break;
- }
-
- //2. retrieve file icons
-#ifdef FFS_WIN
- //perf: optimize fallback case for SIZE_MEDIUM and SIZE_LARGE:
- const Zstring& extension = getFileExtension(filename);
- if (isCheapExtension(extension)) //"pricey" extensions are stored with fullnames and are read from disk, while cheap ones require just the extension
- return getAssociatedIconByExt(extension, sz);
- //result will not be buffered under extension name, but full filename; this is okay, since we're in SIZE_MEDIUM or SIZE_LARGE context,
- //which means the access to get thumbnail failed: thumbnail failure is not dependent from extension in general!
-
- SHFILEINFO fileInfo = {};
- DWORD_PTR imgList = ::SHGetFileInfo(filename.c_str(), //zen::removeLongPathPrefix(fileName), //::SHGetFileInfo() can't handle \\?\-prefix!
- 0,
- &fileInfo,
- sizeof(fileInfo),
- SHGFI_SYSICONINDEX);
- //Quote: "The IImageList pointer type, such as that returned in the ppv parameter, can be cast as an HIMAGELIST as
- // needed; for example, for use in a list view. Conversely, an HIMAGELIST can be cast as a pointer to an IImageList."
- //http://msdn.microsoft.com/en-us/library/windows/desktop/bb762185(v=vs.85).aspx
-
- if (!imgList)
- return NULL;
- //imgList->Release(); //empiric study: crash on XP if we release this! Seems we do not own it... -> also no GDI leak on Win7 -> okay
- //another comment on http://msdn.microsoft.com/en-us/library/bb762179(v=VS.85).aspx describes exact same behavior on Win7/XP
-
- boost::call_once(initGetIconByIndexOnce, []() //thread-safe init
- {
- getIconByIndex = util::DllFun<thumb::GetIconByIndexFct>(thumb::getDllName(), thumb::getIconByIndexFctName);
- });
- return getIconByIndex ? static_cast<HICON>(getIconByIndex(fileInfo.iIcon, getShilIconType(sz))) : NULL;
-
-#elif defined FFS_LINUX
- const int requestedSize = IconBuffer::cvrtSize(sz);
- //call Gtk::Main::init_gtkmm_internals() on application startup!!
- try
- {
- Glib::RefPtr<Gio::File> fileObj = Gio::File::create_for_path(filename.c_str()); //never fails
- Glib::RefPtr<Gio::FileInfo> fileInfo = fileObj->query_info(G_FILE_ATTRIBUTE_STANDARD_ICON);
- if (fileInfo)
- {
- Glib::RefPtr<Gio::Icon> gicon = fileInfo->get_icon();
- if (gicon)
- {
- Glib::RefPtr<Gtk::IconTheme> iconTheme = Gtk::IconTheme::get_default();
- if (iconTheme)
- {
- Gtk::IconInfo iconInfo = iconTheme->lookup_icon(gicon, requestedSize, Gtk::ICON_LOOKUP_USE_BUILTIN); //this may fail if icon is not installed on system
- if (iconInfo)
- {
- Glib::RefPtr<Gdk::Pixbuf> iconPixbuf = iconInfo.load_icon(); //render icon into Pixbuf
- if (iconPixbuf)
- return IconHolder(iconPixbuf->gobj_copy()); //copy and pass icon ownership (may be 0)
- }
- }
- }
- }
- }
- catch (const Glib::Error&) {}
-
- try //fallback: icon lookup may fail because some icons are currently not present on system
- {
- Glib::RefPtr<Gtk::IconTheme> iconTheme = Gtk::IconTheme::get_default();
- if (iconTheme)
- {
- Glib::RefPtr<Gdk::Pixbuf> iconPixbuf = iconTheme->load_icon("misc", requestedSize, Gtk::ICON_LOOKUP_USE_BUILTIN);
- if (!iconPixbuf)
- iconPixbuf = iconTheme->load_icon("text-x-generic", requestedSize, Gtk::ICON_LOOKUP_USE_BUILTIN);
- if (iconPixbuf)
- return IconHolder(iconPixbuf->gobj_copy()); //copy and pass icon ownership (may be 0)
- }
- }
- catch (const Glib::Error&) {}
-
- //fallback fallback
- return IconHolder();
-#endif
-}
-
-
-IconHolder getDirectoryIcon(IconBuffer::IconSize sz)
-{
-#ifdef FFS_WIN
- return getIconByAttribute(L"dummy", //Windows 7 doesn't like this parameter to be an empty string!
- FILE_ATTRIBUTE_DIRECTORY, sz);
-#elif defined FFS_LINUX
- return ::getAssociatedIcon(Zstr("/usr/"), sz); //all directories will look like "/usr/"
-#endif
-}
-
-
-IconHolder getFileIcon(IconBuffer::IconSize sz)
-{
-#ifdef FFS_WIN
- return getIconByAttribute(L"dummy", FILE_ATTRIBUTE_NORMAL, sz);
-#elif defined FFS_LINUX
- const int requestedSize = IconBuffer::cvrtSize(sz);
- try
- {
- Glib::RefPtr<Gtk::IconTheme> iconTheme = Gtk::IconTheme::get_default();
- if (iconTheme)
- {
- Glib::RefPtr<Gdk::Pixbuf> iconPixbuf = iconTheme->load_icon("misc", requestedSize, Gtk::ICON_LOOKUP_USE_BUILTIN);
- if (!iconPixbuf)
- iconPixbuf = iconTheme->load_icon("text-x-generic", requestedSize, Gtk::ICON_LOOKUP_USE_BUILTIN);
- if (iconPixbuf)
- return IconHolder(iconPixbuf->gobj_copy()); // transfer ownership!!
- }
- }
- catch (const Glib::Error&) {}
-
- return IconHolder();
-#endif
-}
-//################################################################################################################################################
-
-
-//---------------------- Shared Data -------------------------
-struct WorkLoad
-{
-public:
- Zstring extractNextFile() //context of worker thread, blocking
- {
- boost::unique_lock<boost::mutex> dummy(lockFiles);
-
- while (filesToLoad.empty())
- conditionNewFiles.timed_wait(dummy, boost::get_system_time() + boost::posix_time::milliseconds(50)); //interruption point!
-
- Zstring fileName = filesToLoad.back();
- filesToLoad.pop_back();
- return fileName;
- }
-
- void setWorkload(const std::vector<Zstring>& newLoad) //context of main thread
- {
- {
- boost::unique_lock<boost::mutex> dummy(lockFiles);
- filesToLoad = newLoad;
- }
- conditionNewFiles.notify_one();
- //condition handling, see: http://www.boost.org/doc/libs/1_43_0/doc/html/thread/synchronization.html#thread.synchronization.condvar_ref
- }
-
-private:
- std::vector<Zstring> filesToLoad; //processes last elements of vector first!
- boost::mutex lockFiles;
- boost::condition_variable conditionNewFiles; //signal event: data for processing available
-};
-
-
-typedef std::map<Zstring, IconHolder, LessFilename> NameIconMap; //entryName/icon -> note: Zstring is thread-safe
-typedef std::queue<Zstring> IconDbSequence; //entryName
-
-class Buffer
-{
-public:
- bool requestFileIcon(const Zstring& fileName, IconHolder* icon = NULL)
- {
- boost::lock_guard<boost::mutex> dummy(lockBuffer);
-
- auto iter = iconMappping.find(fileName);
- if (iter != iconMappping.end())
- {
- if (icon != NULL)
- *icon = iter->second;
- return true;
- }
- return false;
- }
-
- void insertIntoBuffer(const Zstring& entryName, const IconHolder& icon) //called by worker thread
- {
- boost::lock_guard<boost::mutex> dummy(lockBuffer);
-
- //thread saftey: icon uses ref-counting! But is NOT shared with main thread!
- auto rc = iconMappping.insert(std::make_pair(entryName, icon));
- if (rc.second) //if insertion took place
- iconSequence.push(entryName); //note: sharing Zstring with IconDB!!!
-
- assert(iconMappping.size() == iconSequence.size());
-
- //remove elements if buffer becomes too big:
- if (iconMappping.size() > BUFFER_SIZE_MAX) //limit buffer size: critical because GDI resources are limited (e.g. 10000 on XP per process)
- {
- //remove oldest element
- iconMappping.erase(iconSequence.front());
- iconSequence.pop();
- }
- }
-
-private:
- boost::mutex lockBuffer;
- NameIconMap iconMappping; //use synchronisation when accessing this!
- IconDbSequence iconSequence; //save sequence of buffer entry to delete oldest elements
-};
-//-------------------------------------------------------------
-//################################################################################################################################################
-
-class WorkerThread //lifetime is part of icon buffer
-{
-public:
- WorkerThread(const std::shared_ptr<WorkLoad>& workload,
- const std::shared_ptr<Buffer>& buffer,
- IconBuffer::IconSize sz) :
- workload_(workload),
- buffer_(buffer),
- icoSize(sz) {}
-
- void operator()(); //thread entry
-
-private:
- std::shared_ptr<WorkLoad> workload_; //main/worker thread may access different shared_ptr instances safely (even though they have the same target!)
- std::shared_ptr<Buffer> buffer_; //http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/shared_ptr.htm?sess=8153b05b34d890e02d48730db1ff7ddc#ThreadSafety
- const IconBuffer::IconSize icoSize;
-};
-
-
-void WorkerThread::operator()() //thread entry
-{
- //failure to initialize COM for each thread is a source of hard to reproduce bugs: https://sourceforge.net/tracker/?func=detail&aid=3160472&group_id=234430&atid=1093080
-#ifdef FFS_WIN
- //Prerequisites, see thumbnail.h
-
- //1. Initialize COM
- ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
- LOKI_ON_BLOCK_EXIT2(::CoUninitialize());
-
- //2. Initialize system image list
- typedef BOOL (WINAPI *FileIconInitFun)(BOOL fRestoreCache);
- const util::DllFun<FileIconInitFun> fileIconInit(L"Shell32.dll", reinterpret_cast<LPCSTR>(660));
- assert(fileIconInit);
- if (fileIconInit)
- fileIconInit(false); //TRUE to restore the system image cache from disk; FALSE otherwise.
-#endif
-
- while (true)
- {
- boost::this_thread::interruption_point();
-
- const Zstring fileName = workload_->extractNextFile(); //start work: get next icon to load
-
- if (buffer_->requestFileIcon(fileName))
- continue; //icon already in buffer: skip
-
- buffer_->insertIntoBuffer(fileName, getAssociatedIcon(fileName, icoSize));
- }
-}
-//######################### redirect to impl #####################################################
-
-struct IconBuffer::Pimpl
-{
- Pimpl() :
- workload(std::make_shared<WorkLoad>()),
- buffer(std::make_shared<Buffer>()) {}
-
- std::shared_ptr<WorkLoad> workload;
- std::shared_ptr<Buffer> buffer;
-
- boost::thread worker;
-};
-
-
-IconBuffer::IconBuffer(IconSize sz) :
- pimpl(new Pimpl),
- icoSize(sz),
- genDirIcon(::getDirectoryIcon(sz).toWxIcon(cvrtSize(icoSize))),
- genFileIcon(::getFileIcon(sz).toWxIcon(cvrtSize(icoSize)))
-{
- pimpl->worker = boost::thread(WorkerThread(pimpl->workload, pimpl->buffer, sz));
-}
-
-
-IconBuffer::~IconBuffer()
-{
- setWorkload(std::vector<Zstring>()); //make sure interruption point is always reached!
- pimpl->worker.interrupt();
- pimpl->worker.join();
-}
-
-
-bool IconBuffer::requestFileIcon(const Zstring& filename, wxIcon* icon)
-{
- auto getIcon = [&](const Zstring& entryName) -> bool
- {
- if (!icon)
- return pimpl->buffer->requestFileIcon(entryName);
-
- IconHolder heldIcon;
- if (!pimpl->buffer->requestFileIcon(entryName, &heldIcon))
- return false;
- *icon = heldIcon.toWxIcon(cvrtSize(icoSize));
- return true;
- };
-
-#ifdef FFS_WIN
- //perf: let's read icons which don't need file access right away! No async delay justified!
- if (icoSize == IconBuffer::SIZE_SMALL) //non-thumbnail view, we need file type icons only!
- {
- const Zstring& extension = getFileExtension(filename);
- if (isCheapExtension(extension)) //"pricey" extensions are stored with fullnames and are read from disk, while cheap ones require just the extension
- {
- if (!getIcon(extension))
- {
- IconHolder heldIcon = getAssociatedIconByExt(extension, icoSize); //fast!
- pimpl->buffer->insertIntoBuffer(extension, heldIcon);
- if (icon)
- *icon = heldIcon.toWxIcon(cvrtSize(icoSize));
- }
- return true;
- }
- }
-#endif
-
- return getIcon(filename);
-}
-
-void IconBuffer::setWorkload(const std::vector<Zstring>& load) { pimpl->workload->setWorkload(load); }
diff --git a/library/icon_buffer.h b/library/icon_buffer.h
deleted file mode 100644
index cbd582f2..00000000
--- a/library/icon_buffer.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#ifndef ICONBUFFER_H_INCLUDED
-#define ICONBUFFER_H_INCLUDED
-
-#include "../shared/zstring.h"
-#include <memory>
-#include <wx/icon.h>
-
-
-namespace zen
-{
-class IconBuffer
-{
-public:
- enum IconSize
- {
- SIZE_SMALL,
- SIZE_MEDIUM,
- SIZE_LARGE
- };
-
- IconBuffer(IconSize sz);
- ~IconBuffer();
-
- int getSize() const { return cvrtSize(icoSize); } //*maximum* icon size in pixel
-
- const wxIcon& genericDirIcon () { return genDirIcon; }
- const wxIcon& genericFileIcon() { return genFileIcon; }
-
- bool requestFileIcon(const Zstring& filename, wxIcon* icon = NULL); //returns false if icon is not in buffer
- void setWorkload(const std::vector<Zstring>& load); //(re-)set new workload of icons to be retrieved;
-
- static int cvrtSize(IconSize sz);
-
-private:
- struct Pimpl;
- std::unique_ptr<Pimpl> pimpl;
-
- const IconSize icoSize;
- const wxIcon genDirIcon;
- const wxIcon genFileIcon;
-};
-}
-
-#endif // ICONBUFFER_H_INCLUDED
diff --git a/library/lock_holder.h b/library/lock_holder.h
deleted file mode 100644
index b72b12c1..00000000
--- a/library/lock_holder.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef LOCK_HOLDER_H_INCLUDED
-#define LOCK_HOLDER_H_INCLUDED
-
-#include <map>
-#include "../shared/zstring.h"
-#include "dir_lock.h"
-#include "status_handler.h"
-#include "dir_exist_async.h"
-
-namespace zen
-{
-const Zstring LOCK_FILE_ENDING = Zstr(".ffs_lock"); //intermediate locks created by DirLock use this extension, too!
-
-//convenience class for creating and holding locks for a number of directories
-class LockHolder
-{
-public:
- void addDir(const Zstring& dirnameFmt, ProcessCallback& procCallback) //resolved dirname ending with path separator
- {
- if (dirnameFmt.empty())
- return;
-
- if (!dirExistsUpdating(dirnameFmt, procCallback))
- return;
-
- if (lockHolder.find(dirnameFmt) != lockHolder.end()) return;
- assert(dirnameFmt.EndsWith(FILE_NAME_SEPARATOR)); //this is really the contract, formatting does other things as well, e.g. macro substitution
-
- class WaitOnLockHandler : public DirLockCallback
- {
- public:
- WaitOnLockHandler(ProcessCallback& pc) : pc_(pc) {}
- virtual void requestUiRefresh() { pc_.requestUiRefresh(); } //allowed to throw exceptions
- virtual void reportInfo(const std::wstring& text) { pc_.reportStatus(text); }
- private:
- ProcessCallback& pc_;
- } callback(procCallback);
-
- try
- {
- lockHolder.insert(std::make_pair(dirnameFmt, DirLock(dirnameFmt + Zstr("sync") + LOCK_FILE_ENDING, &callback)));
- }
- catch (const FileError& e)
- {
- bool dummy = false; //this warning shall not be shown but logged only
- procCallback.reportWarning(e.msg(), dummy); //may throw!
- }
- }
-
-private:
- typedef std::map<Zstring, DirLock, LessFilename> DirnameLockMap;
- DirnameLockMap lockHolder;
-};
-
-}
-
-
-#endif // LOCK_HOLDER_H_INCLUDED
diff --git a/library/norm_filter.h b/library/norm_filter.h
deleted file mode 100644
index 609c81db..00000000
--- a/library/norm_filter.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#ifndef NORM_FILTER_H_INCLUDED
-#define NORM_FILTER_H_INCLUDED
-
-#include "hard_filter.h"
-#include "soft_filter.h"
-
-namespace zen
-{
-
-struct NormalizedFilter //grade-a filter: global/local filter settings combined, units resolved, ready for use
-{
- NormalizedFilter(const HardFilter::FilterRef& hf, const SoftFilter& sf) : nameFilter(hf), timeSizeFilter(sf) {}
-
- //"hard" filter: relevant during comparison, physically skips files
- HardFilter::FilterRef nameFilter;
- //"soft" filter: relevant after comparison; equivalent to user selection
- SoftFilter timeSizeFilter;
-};
-namespace
-{
-//combine global and local filters via "logical and"
-NormalizedFilter normalizeFilters(const FilterConfig& global, const FilterConfig& local);
-
-inline
-bool isNullFilter(const FilterConfig& filterCfg)
-{
- return NameFilter(filterCfg.includeFilter, filterCfg.excludeFilter).isNull() &&
- SoftFilter(filterCfg.timeSpan, filterCfg.unitTimeSpan,
- filterCfg.sizeMin, filterCfg.unitSizeMin,
- filterCfg.sizeMax, filterCfg.unitSizeMax).isNull();
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-// ----------------------- implementation -----------------------
-NormalizedFilter normalizeFilters(const FilterConfig& global, const FilterConfig& local)
-{
- HardFilter::FilterRef globalName(new NameFilter(global.includeFilter, global.excludeFilter));
- HardFilter::FilterRef localName (new NameFilter(local .includeFilter, local .excludeFilter));
-
- SoftFilter globalTimeSize(global.timeSpan, global.unitTimeSpan,
- global.sizeMin, global.unitSizeMin,
- global.sizeMax, global.unitSizeMax);
-
- SoftFilter localTimeSize(local.timeSpan, local.unitTimeSpan,
- local.sizeMin, local.unitSizeMin,
- local.sizeMax, local.unitSizeMax);
-
- return NormalizedFilter(combineFilters(globalName, localName),
- combineFilters(globalTimeSize, localTimeSize));
-}
-}
-}
-
-#endif //NORM_FILTER_H_INCLUDED
diff --git a/library/parallel_scan.cpp b/library/parallel_scan.cpp
deleted file mode 100644
index 2c24600f..00000000
--- a/library/parallel_scan.cpp
+++ /dev/null
@@ -1,611 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#include "parallel_scan.h"
-#include <boost/detail/atomic_count.hpp>
-#include "db_file.h"
-#include "lock_holder.h"
-#include "../shared/i18n.h"
-#include "../shared/file_traverser.h"
-#include "../shared/file_error.h"
-#include "../shared/string_conv.h"
-#include "../shared/boost_thread_wrap.h" //include <boost/thread.hpp>
-#include "loki/ScopeGuard.h"
-//#include "../shared/file_id.h"
-
-/*
-#ifdef FFS_WIN
-#include <wx/msw/wrapwin.h> //includes "windows.h"
-#include "WinIoCtl.h"
-
-#elif defined FFS_LINUX
-#endif
-*/
-using namespace zen;
-
-
-#ifndef BOOST_HAS_THREADS
-#error just some paranoia check...
-#endif
-
-
-namespace
-{
-/*
-#ifdef FFS_WIN
-
-struct DiskInfo
-{
- DiskInfo() :
- driveType(DRIVE_UNKNOWN),
- diskID(-1) {}
-
- UINT driveType;
- int diskID; // -1 if id could not be determined, this one is filled if driveType == DRIVE_FIXED or DRIVE_REMOVABLE;
-};
-
-inline
-bool operator<(const DiskInfo& lhs, const DiskInfo& rhs)
-{
- if (lhs.driveType != rhs.driveType)
- return lhs.driveType < rhs.driveType;
-
- if (lhs.diskID < 0 || rhs.diskID < 0)
- return false;
- //consider "same", reason: one volume may be uniquely associated with one disk, while the other volume is associated to the same disk AND another one!
- //volume <-> disk is 0..N:1..N
-
- return lhs.diskID < rhs.diskID ;
-}
-
-
-DiskInfo retrieveDiskInfo(const Zstring& pathName)
-{
- std::vector<wchar_t> volName(std::max(pathName.size(), static_cast<size_t>(10000)));
-
- DiskInfo output;
-
- //full pathName need not yet exist!
- if (!::GetVolumePathName(pathName.c_str(), //__in LPCTSTR lpszFileName,
- &volName[0], //__out LPTSTR lpszVolumePathName,
- static_cast<DWORD>(volName.size()))) //__in DWORD cchBufferLength
- return output;
-
- const Zstring rootPathName = &volName[0];
-
- output.driveType = ::GetDriveType(rootPathName.c_str());
-
- if (output.driveType == DRIVE_NO_ROOT_DIR) //these two should be the same error category
- output.driveType = DRIVE_UNKNOWN;
-
- if (output.driveType != DRIVE_FIXED && output.driveType != DRIVE_REMOVABLE)
- return output; //no reason to get disk ID
-
- //go and find disk id:
-
- //format into form: "\\.\C:"
- Zstring volnameFmt = rootPathName;
- if (endsWith(volnameFmt, FILE_NAME_SEPARATOR))
- volnameFmt.resize(volnameFmt.size() - 1);
- volnameFmt = L"\\\\.\\" + volnameFmt;
-
- HANDLE hVolume = ::CreateFile(volnameFmt.c_str(),
- 0,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- 0,
- OPEN_EXISTING,
- 0,
- NULL);
- if (hVolume == INVALID_HANDLE_VALUE)
- return output;
- LOKI_ON_BLOCK_EXIT2(::CloseHandle(hVolume));
-
- std::vector<char> buffer(sizeof(VOLUME_DISK_EXTENTS) + sizeof(DISK_EXTENT)); //reserve buffer for at most one disk! call below will then fail if volume spans multiple disks!
-
- DWORD bytesReturned = 0;
- if (!::DeviceIoControl(hVolume, // handle to device
- IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, // dwIoControlCode
- NULL, // lpInBuffer
- 0, // nInBufferSize
- &buffer[0], // output buffer
- static_cast<DWORD>(buffer.size()), // size of output buffer
- &bytesReturned, // number of bytes returned
- NULL)) // OVERLAPPED structure
- return output;
-
- const VOLUME_DISK_EXTENTS& volDisks = *reinterpret_cast<VOLUME_DISK_EXTENTS*>(&buffer[0]);
-
- if (volDisks.NumberOfDiskExtents != 1)
- return output;
-
- output.diskID = volDisks.Extents[0].DiskNumber;
-
- return output;
-}
-
-#elif defined FFS_LINUX
-#endif
-*/
-
-/*
-PERF NOTE
-
---------------------------------------------
-|Testcase: Reading from two different disks|
---------------------------------------------
-Windows 7:
- 1st(unbuffered) |2nd (OS buffered)
- ----------------------------------
-1 Thread: 57s | 8s
-2 Threads: 39s | 7s
-
---------------------------------------------------
-|Testcase: Reading two directories from same disk|
---------------------------------------------------
-Windows 7: Windows XP:
- 1st(unbuffered) |2nd (OS buffered) 1st(unbuffered) |2nd (OS buffered)
- ---------------------------------- ----------------------------------
-1 Thread: 41s | 13s 1 Thread: 45s | 13s
-2 Threads: 42s | 11s 2 Threads: 38s | 8s
-
-=> Traversing does not take any advantage of file locality so that even multiple threads operating on the same disk impose no performance overhead.
-*/
-
-
-std::vector<std::set<DirectoryKey>> separateByDistinctDisk(const std::set<DirectoryKey>& dirkeys)
-{
- //see perf note: use one thread per dirkey:
- typedef std::map<int, std::set<DirectoryKey>> DiskKeyMapping;
- DiskKeyMapping tmp;
- int index = 0;
- std::for_each(dirkeys.begin(), dirkeys.end(),
- [&](const DirectoryKey& key) { tmp[++index].insert(key); });
-
- /*
- //use one thread per physical disk:
- typedef std::map<DiskInfo, std::set<DirectoryKey>> DiskKeyMapping;
- DiskKeyMapping tmp;
- std::for_each(dirkeys.begin(), dirkeys.end(),
- [&](const DirectoryKey& key) { tmp[retrieveDiskInfo(key.dirnameFull_)].insert(key); });
- */
- std::vector<std::set<DirectoryKey>> buckets;
- std::transform(tmp.begin(), tmp.end(), std::back_inserter(buckets),
- [&](const DiskKeyMapping::value_type& diskToKey) { return diskToKey.second; });
- return buckets;
-}
-
-//------------------------------------------------------------------------------------------
-typedef Zbase<wchar_t, StorageRefCountThreadSafe> BasicWString; //thread safe string class for UI texts
-
-
-class AsyncCallback
-{
-public:
- AsyncCallback() :
- notifyingThreadID(-1),
- textScanning(_("Scanning:")),
- itemsScanned(0),
- activeWorker(0) {}
-
- FillBufferCallback::HandleError reportError(const std::wstring& msg) //blocking call: context of worker thread
- {
- boost::unique_lock<boost::mutex> dummy(lockErrorMsg);
- while (!errorMsg.empty() || errorResponse.get())
- conditionCanReportError.timed_wait(dummy, boost::posix_time::milliseconds(50)); //interruption point!
-
- errorMsg = BasicWString(msg);
-
- while (!errorResponse.get())
- conditionGotResponse.timed_wait(dummy, boost::posix_time::milliseconds(50)); //interruption point!
-
- FillBufferCallback::HandleError rv = *errorResponse;
-
- errorMsg.clear();
- errorResponse.reset();
-
- //dummy.unlock();
- conditionCanReportError.notify_one();
-
- return rv;
- }
-
- void processErrors(FillBufferCallback& callback) //context of main thread, call repreatedly
- {
- boost::lock_guard<boost::mutex> dummy(lockErrorMsg);
- if (!errorMsg.empty() && !errorResponse.get())
- {
- FillBufferCallback::HandleError rv = callback.reportError(cvrtString<std::wstring>(errorMsg)); //throw!
- errorResponse.reset(new FillBufferCallback::HandleError(rv));
-
- //dummy.unlock();
- conditionGotResponse.notify_one();
- }
- }
-
- void setNotifyingThread(int threadID) { notifyingThreadID = threadID; } //context of main thread
-
- void reportCurrentFile(const Zstring& filename, int threadID) //context of worker thread
- {
- if (threadID != notifyingThreadID) return; //only one thread may report status
-
- boost::lock_guard<boost::mutex> dummy(lockCurrentStatus);
- currentFile = filename;
- currentStatus.clear();
- }
-
- void reportCurrentStatus(const std::wstring& status, int threadID) //context of worker thread
- {
- if (threadID != notifyingThreadID) return; //only one thread may report status
-
- boost::lock_guard<boost::mutex> dummy(lockCurrentStatus);
- currentFile.clear();
- currentStatus = BasicWString(status); //we cannot assume std::wstring to be thread safe (yet)!
- }
-
- std::wstring getCurrentStatus() //context of main thread, call repreatedly
- {
- std::wstring filename;
- std::wstring statusMsg;
- {
- boost::lock_guard<boost::mutex> dummy(lockCurrentStatus);
- if (!currentFile.empty())
- filename = utf8CvrtTo<std::wstring>(currentFile);
- else if (!currentStatus.empty())
- statusMsg = cvrtString<std::wstring>(currentStatus);
- }
-
- if (!filename.empty())
- {
- std::wstring statusText = cvrtString<std::wstring>(textScanning);
- const long activeCount = activeWorker;
- if (activeCount >= 2)
- {
- statusText += L" " + _P("[1 Thread]", "[%x Threads]", activeCount);
- replace(statusText, L"%x", toString<std::wstring>(activeCount));
- }
- statusText += std::wstring(L" \n") + L'\"' + filename + L'\"';
- return statusText;
- }
- else
- return statusMsg;
- }
-
- void incItemsScanned() { ++itemsScanned; }
- long getItemsScanned() const { return itemsScanned; }
-
- void incActiveWorker() { ++activeWorker; }
- void decActiveWorker() { --activeWorker; }
- long getActiveWorker() const { return activeWorker; }
-
-private:
- //---- error handling ----
- boost::mutex lockErrorMsg;
- boost::condition_variable conditionCanReportError;
- boost::condition_variable conditionGotResponse;
- BasicWString errorMsg;
- std::unique_ptr<FillBufferCallback::HandleError> errorResponse;
-
- //---- status updates ----
- volatile int notifyingThreadID; //theoretically racy, but there is nothing that could go wrong...
- //CAVEAT: do NOT use boost::thread::id as long as this showstopper exists: https://svn.boost.org/trac/boost/ticket/5754
- boost::mutex lockCurrentStatus; //use a different lock for current file: continue traversing while some thread may process an error
- Zstring currentFile; //only one of these two is filled at a time!
- BasicWString currentStatus; //
-
- const BasicWString textScanning; //this one is (currently) not shared and could be made a std::wstring, but we stay consistent and use thread-safe variables in this class only!
-
- //---- status updates II (lock free) ----
- boost::detail::atomic_count itemsScanned;
- boost::detail::atomic_count activeWorker;
-};
-//-------------------------------------------------------------------------------------------------
-
-class DirCallback;
-
-struct TraverserShared
-{
-public:
- TraverserShared(int threadID,
- SymLinkHandling handleSymlinks,
- const HardFilter::FilterRef& filter,
- std::set<Zstring>& failedReads,
- AsyncCallback& acb) :
- handleSymlinks_(handleSymlinks),
- filterInstance(filter),
- failedReads_(failedReads),
- acb_(acb),
- threadID_(threadID) {}
-
- typedef std::shared_ptr<DirCallback> CallbackPointer;
- std::vector<CallbackPointer> callBackBox; //collection of callback pointers to handle ownership
-
- const SymLinkHandling handleSymlinks_;
- const HardFilter::FilterRef filterInstance; //always bound!
-
- std::set<Zstring>& failedReads_; //relative postfixed names of directories that could not be read (empty for root)
-
- AsyncCallback& acb_;
- int threadID_;
-};
-
-
-class DirCallback : public zen::TraverseCallback
-{
-public:
- DirCallback(TraverserShared& config,
- const Zstring& relNameParentPf, //postfixed with FILE_NAME_SEPARATOR!
- DirContainer& output) :
- cfg(config),
- relNameParentPf_(relNameParentPf),
- output_(output) {}
-
- virtual void onFile (const Zchar* shortName, const Zstring& fullName, const FileInfo& details);
- virtual void onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details);
- virtual ReturnValDir onDir (const Zchar* shortName, const Zstring& fullName);
- virtual HandleError onError (const std::wstring& errorText);
-
-private:
- TraverserShared& cfg;
- const Zstring relNameParentPf_;
- DirContainer& output_;
-};
-
-
-void DirCallback::onFile(const Zchar* shortName, const Zstring& fullName, const FileInfo& details)
-{
- boost::this_thread::interruption_point();
-
- const Zstring fileNameShort = shortName;
-
- //do not list the database file(s) sync.ffs_db, sync.x64.ffs_db, etc. or lock files
- if (endsWith(fileNameShort, SYNC_DB_FILE_ENDING) ||
- endsWith(fileNameShort, LOCK_FILE_ENDING))
- return;
-
- //update status information no matter whether object is excluded or not!
- cfg.acb_.reportCurrentFile(fullName, cfg.threadID_);
-
- //------------------------------------------------------------------------------------
- //apply filter before processing (use relative name!)
- if (!cfg.filterInstance->passFileFilter(relNameParentPf_ + fileNameShort))
- return;
-
- // std::string fileId = details.fileSize >= 1024 * 1024U ?
- // util::retrieveFileID(fullName) :
- // std::string();
- /*
- Perf test Windows 7, SSD, 350k files, 50k dirs, files > 1MB: 7000
- regular: 6.9s
- ID per file: 43.9s
- ID per file > 1MB: 7.2s
- ID per dir: 8.4s
-
- Linux: retrieveFileID takes about 50% longer in VM! (avoidable because of redundant stat() call!)
- */
-
- output_.addSubFile(fileNameShort, FileDescriptor(details.lastWriteTimeRaw, details.fileSize));
-
- cfg.acb_.incItemsScanned(); //add 1 element to the progress indicator
-}
-
-
-void DirCallback::onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details)
-{
- boost::this_thread::interruption_point();
-
- if (cfg.handleSymlinks_ == SYMLINK_IGNORE)
- return;
-
- //update status information no matter whether object is excluded or not!
- cfg.acb_.reportCurrentFile(fullName, cfg.threadID_);
-
- //------------------------------------------------------------------------------------
- const Zstring& relName = relNameParentPf_ + shortName;
-
- //apply filter before processing (use relative name!)
- if (!cfg.filterInstance->passFileFilter(relName)) //always use file filter: Link type may not be "stable" on Linux!
- return;
-
- output_.addSubLink(shortName, LinkDescriptor(details.lastWriteTimeRaw, details.targetPath, details.dirLink ? LinkDescriptor::TYPE_DIR : LinkDescriptor::TYPE_FILE));
-
- cfg.acb_.incItemsScanned(); //add 1 element to the progress indicator
-}
-
-
-TraverseCallback::ReturnValDir DirCallback::onDir(const Zchar* shortName, const Zstring& fullName)
-{
- boost::this_thread::interruption_point();
-
- //update status information no matter whether object is excluded or not!
- cfg.acb_.reportCurrentFile(fullName, cfg.threadID_);
-
- //------------------------------------------------------------------------------------
- const Zstring& relName = relNameParentPf_ + shortName;
-
- //apply filter before processing (use relative name!)
- bool subObjMightMatch = true;
- const bool passFilter = cfg.filterInstance->passDirFilter(relName, &subObjMightMatch);
- if (!passFilter && !subObjMightMatch)
- return Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_IGNORE>(); //do NOT traverse subdirs
- //else: attention! ensure directory filtering is applied later to exclude actually filtered directories
-
- DirContainer& subDir = output_.addSubDir(shortName);
- if (passFilter)
- cfg.acb_.incItemsScanned(); //add 1 element to the progress indicator
-
- TraverserShared::CallbackPointer subDirCallback = std::make_shared<DirCallback>(cfg, relName + FILE_NAME_SEPARATOR, subDir);
- cfg.callBackBox.push_back(subDirCallback); //handle lifetime
- return ReturnValDir(Loki::Int2Type<ReturnValDir::TRAVERSING_DIR_CONTINUE>(), *subDirCallback);
-}
-
-
-DirCallback::HandleError DirCallback::onError(const std::wstring& errorText)
-{
- switch (cfg.acb_.reportError(errorText))
- {
- case FillBufferCallback::TRAV_ERROR_IGNORE:
- cfg.failedReads_.insert(relNameParentPf_);
- return TRAV_ERROR_IGNORE;
-
- case FillBufferCallback::TRAV_ERROR_RETRY:
- return TRAV_ERROR_RETRY;
- }
-
- assert(false);
- return TRAV_ERROR_IGNORE;
-}
-
-
-#ifdef FFS_WIN
-class DstHackCallbackImpl : public DstHackCallback
-{
-public:
- DstHackCallbackImpl(AsyncCallback& acb, int threadID) :
- acb_(acb),
- threadID_(threadID),
- textApplyingDstHack(toZ(_("Encoding extended time information: %x")).Replace(Zstr("%x"), Zstr("\n\"%x\""))) {}
-
-private:
- virtual void requestUiRefresh(const Zstring& filename) //applying DST hack imposes significant one-time performance drawback => callback to inform user
- {
- Zstring statusText = textApplyingDstHack;
- replace(statusText, Zstr("%x"), filename);
- acb_.reportCurrentStatus(utf8CvrtTo<std::wstring>(statusText), threadID_);
- }
-
- AsyncCallback& acb_;
- int threadID_;
- const Zstring textApplyingDstHack;
-};
-#endif
-//------------------------------------------------------------------------------------------
-
-
-class WorkerThread
-{
-public:
- WorkerThread(int threadID,
- const std::shared_ptr<AsyncCallback>& acb,
- const std::vector<std::pair<DirectoryKey, DirectoryValue*>>& workload) :
- threadID_(threadID),
- acb_(acb),
- workload_(workload) {}
-
- void operator()() //thread entry
- {
- acb_->incActiveWorker();
- LOKI_ON_BLOCK_EXIT2(acb_->decActiveWorker(););
-
- std::for_each(workload_.begin(), workload_.end(),
- [&](std::pair<DirectoryKey, DirectoryValue*>& item)
- {
- const Zstring& directoryName = item.first.dirnameFull_;
- DirectoryValue& dirVal = *item.second;
-
- acb_->reportCurrentFile(directoryName, threadID_); //just in case first directory access is blocking
-
- TraverserShared travCfg(threadID_,
- item.first.handleSymlinks_, //shared by all(!) instances of DirCallback while traversing a folder hierarchy
- item.first.filter_,
- dirVal.failedReads,
- *acb_);
-
- DirCallback traverser(travCfg,
- Zstring(),
- dirVal.dirCont);
-
- bool followSymlinks = false;
- switch (item.first.handleSymlinks_)
- {
- case SYMLINK_IGNORE:
- followSymlinks = false; //=> symlinks will be reported via onSymlink() where they are excluded
- break;
- case SYMLINK_USE_DIRECTLY:
- followSymlinks = false;
- break;
- case SYMLINK_FOLLOW_LINK:
- followSymlinks = true;
- break;
- }
-
- DstHackCallback* dstCallbackPtr = NULL;
-#ifdef FFS_WIN
- DstHackCallbackImpl dstCallback(*acb_, threadID_);
- dstCallbackPtr = &dstCallback;
-#endif
-
- //get all files and folders from directoryPostfixed (and subdirectories)
- traverseFolder(directoryName, followSymlinks, traverser, dstCallbackPtr); //exceptions may be thrown!
- });
- }
-
-private:
- int threadID_;
- std::shared_ptr<AsyncCallback> acb_;
- std::vector<std::pair<DirectoryKey, DirectoryValue*>> workload_;
-};
-}
-
-
-void zen::fillBuffer(const std::set<DirectoryKey>& keysToRead, //in
- std::map<DirectoryKey, DirectoryValue>& buf, //out
- FillBufferCallback& callback,
- size_t statusInterval)
-{
- buf.clear();
-
- std::vector<std::set<DirectoryKey>> buckets = separateByDistinctDisk(keysToRead); //one bucket per physical device
-
- std::vector<boost::thread> worker; //note: GCC doesn't allow to construct an array of empty threads since they would be initialized by const boost::thread&
- worker.reserve(buckets.size());
-
- Loki::ScopeGuard guardWorker = Loki::MakeGuard([&]()
- {
- std::for_each(worker.begin(), worker.end(), std::mem_fun_ref(&boost::thread::interrupt)); //interrupt all at once, then join
- std::for_each(worker.begin(), worker.end(), std::mem_fun_ref(&boost::thread::join));
- });
-
- std::shared_ptr<AsyncCallback> acb = std::make_shared<AsyncCallback>();
-
- //init worker threads
- for (auto iter = buckets.begin(); iter != buckets.end(); ++iter)
- {
- int threadID = iter - buckets.begin();
- const std::set<DirectoryKey>& bucket = *iter;
-
- std::vector<std::pair<DirectoryKey, DirectoryValue*>> workload;
- std::for_each(bucket.begin(), bucket.end(),
- [&](const DirectoryKey& key)
- {
- auto rv = buf.insert(std::make_pair(key, DirectoryValue()));
- assert(rv.second);
- workload.push_back(std::make_pair(key, &rv.first->second));
- });
-
- worker.push_back(boost::thread(WorkerThread(threadID, acb, workload)));
- }
-
- //wait until done
- for (auto iter = worker.begin(); iter != worker.end(); ++iter)
- {
- boost::thread& wt = *iter;
- int threadID = iter - worker.begin();
-
- acb->setNotifyingThread(threadID); //process info messages of first (active) thread only
-
- do
- {
- //update status
- callback.reportStatus(acb->getCurrentStatus(), acb->getItemsScanned()); //throw!
-
- //process errors
- acb->processErrors(callback);
- }
- while (!wt.timed_join(boost::posix_time::milliseconds(statusInterval)));
- }
-
- guardWorker.Dismiss();
-}
diff --git a/library/parallel_scan.h b/library/parallel_scan.h
deleted file mode 100644
index 5c998969..00000000
--- a/library/parallel_scan.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#ifndef PARALLEL_SCAN_H_INCLUDED
-#define PARALLEL_SCAN_H_INCLUDED
-
-#include <map>
-#include <set>
-#include "hard_filter.h"
-#include "../structures.h"
-#include "../file_hierarchy.h"
-
-namespace zen
-{
-struct DirectoryKey
-{
- DirectoryKey(const Zstring& dirnameFull,
- const HardFilter::FilterRef& filter,
- SymLinkHandling handleSymlinks) :
- dirnameFull_(dirnameFull),
- filter_(filter),
- handleSymlinks_(handleSymlinks) {}
-
- Zstring dirnameFull_;
- HardFilter::FilterRef filter_; //filter interface: always bound by design!
- SymLinkHandling handleSymlinks_;
-};
-
-inline
-bool operator<(const DirectoryKey& lhs, const DirectoryKey& rhs)
-{
- if (lhs.handleSymlinks_ != rhs.handleSymlinks_)
- return lhs.handleSymlinks_ < rhs.handleSymlinks_;
-
- if (!EqualFilename()(lhs.dirnameFull_, rhs.dirnameFull_))
- return LessFilename()(lhs.dirnameFull_, rhs.dirnameFull_);
-
- return *lhs.filter_ < *rhs.filter_;
-}
-
-
-struct DirectoryValue
-{
- DirContainer dirCont;
- std::set<Zstring> failedReads; //relative postfixed names of directories that could not be read (empty string for root), e.g. access denied, or temporal network drop
-};
-
-
-class FillBufferCallback
-{
-public:
- virtual ~FillBufferCallback() {}
-
- enum HandleError
- {
- TRAV_ERROR_RETRY,
- TRAV_ERROR_IGNORE
- };
- virtual HandleError reportError (const std::wstring& errorText) = 0; //may throw!
- virtual void reportStatus(const std::wstring& statusMsg, int itemTotal) = 0; //
-};
-
-//attention: ensure directory filtering is applied later to exclude filtered directories which have been kept as parent folders
-
-void fillBuffer(const std::set<DirectoryKey>& keysToRead, //in
- std::map<DirectoryKey, DirectoryValue>& buf, //out
- FillBufferCallback& callback,
- size_t statusInterval); //unit: [ms]
-}
-
-#endif // PARALLEL_SCAN_H_INCLUDED
diff --git a/library/process_xml.cpp b/library/process_xml.cpp
deleted file mode 100644
index 8362e073..00000000
--- a/library/process_xml.cpp
+++ /dev/null
@@ -1,1172 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#include "process_xml.h"
-#include <zenXml/zenxml.h>
-#include "../shared/i18n.h"
-#include "../shared/global_func.h"
-#include "../shared/standard_paths.h"
-#include "../shared/string_conv.h"
-#include "../shared/file_handling.h"
-#include "../shared/file_io.h"
-#include "../shared/xml_base.h"
-
-using namespace zen;
-using namespace xmlAccess; //functionally needed for correct overload resolution!!!
-
-
-XmlType getXmlType(const zen::XmlDoc& doc) //throw()
-{
- if (doc.root().getNameAs<std::string>() == "FreeFileSync")
- {
- std::string type;
- if (doc.root().getAttribute("XmlType", type))
- {
- if (type == "GUI")
- return XML_TYPE_GUI;
- else if (type == "BATCH")
- return XML_TYPE_BATCH;
- else if (type == "GLOBAL")
- return XML_TYPE_GLOBAL;
- }
- }
- return XML_TYPE_OTHER;
-}
-
-
-XmlType xmlAccess::getXmlType(const wxString& filename) //throw()
-{
- XmlDoc doc;
- try
- {
- //do NOT use zen::loadStream as it will superfluously load even huge files!
- loadXmlDocument(filename, doc); //throw FfsXmlError, quick exit if file is not an FFS XML
- }
- catch (const FfsXmlError&)
- {
- return XML_TYPE_OTHER;
- }
- return ::getXmlType(doc);
-}
-
-
-void setXmlType(XmlDoc& doc, XmlType type) //throw()
-{
- switch (type)
- {
- case XML_TYPE_GUI:
- doc.root().setAttribute("XmlType", "GUI");
- break;
- case XML_TYPE_BATCH:
- doc.root().setAttribute("XmlType", "BATCH");
- break;
- case XML_TYPE_GLOBAL:
- doc.root().setAttribute("XmlType", "GLOBAL");
- break;
- case XML_TYPE_OTHER:
- assert(false);
- break;
- }
-}
-//################################################################################################################
-
-
-wxString xmlAccess::getGlobalConfigFile()
-{
- return zen::getConfigDir() + wxT("GlobalSettings.xml");
-}
-
-
-void xmlAccess::OptionalDialogs::resetDialogs()
-{
- warningDependentFolders = true;
- warningMultiFolderWriteAccess = true;
- warningSignificantDifference = true;
- warningNotEnoughDiskSpace = true;
- warningUnresolvedConflicts = true;
- warningSyncDatabase = true;
- warningRecyclerMissing = true;
- popupOnConfigChange = true;
- showSummaryBeforeSync = true;
-}
-
-
-xmlAccess::XmlGuiConfig xmlAccess::convertBatchToGui(const xmlAccess::XmlBatchConfig& batchCfg)
-{
- XmlGuiConfig output;
- output.mainCfg = batchCfg.mainCfg;
-
- switch (batchCfg.handleError)
- {
- case ON_ERROR_EXIT:
- case ON_ERROR_POPUP:
- output.handleError = ON_GUIERROR_POPUP;
- break;
- case ON_ERROR_IGNORE:
- output.handleError = ON_GUIERROR_IGNORE;
- break;
- }
- return output;
-}
-
-
-xmlAccess::XmlBatchConfig xmlAccess::convertGuiToBatch(const xmlAccess::XmlGuiConfig& guiCfg, const wxString& referenceFile)
-{
- //try to take over batch-specific settings from reference
- if (!referenceFile.empty() && getXmlType(referenceFile) == XML_TYPE_BATCH)
- try
- {
- XmlBatchConfig output;
-
- std::vector<wxString> filenames;
- filenames.push_back(referenceFile);
- convertConfig(filenames, output); //throw xmlAccess::FfsXmlError
-
- output.mainCfg = guiCfg.mainCfg;
- return output;
- }
- catch (xmlAccess::FfsXmlError&) {}
-
- XmlBatchConfig output; //use default batch-settings
- output.mainCfg = guiCfg.mainCfg;
-
- switch (guiCfg.handleError)
- {
- case ON_GUIERROR_POPUP:
- output.handleError = ON_ERROR_POPUP;
- break;
- case ON_GUIERROR_IGNORE:
- output.handleError = ON_ERROR_IGNORE;
- break;
- }
-
- return output;
-}
-
-
-xmlAccess::MergeType xmlAccess::getMergeType(const std::vector<wxString>& filenames) //throw ()
-{
- bool guiCfgExists = false;
- bool batchCfgExists = false;
-
- for (std::vector<wxString>::const_iterator i = filenames.begin(); i != filenames.end(); ++i)
- {
- switch (xmlAccess::getXmlType(*i)) //throw()
- {
- case XML_TYPE_GUI:
- guiCfgExists = true;
- break;
-
- case XML_TYPE_BATCH:
- batchCfgExists = true;
- break;
-
- case XML_TYPE_GLOBAL:
- case XML_TYPE_OTHER:
- return MERGE_OTHER;
- }
- }
-
- if (guiCfgExists && batchCfgExists)
- return MERGE_GUI_BATCH;
- else if (guiCfgExists && !batchCfgExists)
- return MERGE_GUI;
- else if (!guiCfgExists && batchCfgExists)
- return MERGE_BATCH;
- else
- return MERGE_OTHER;
-}
-
-
-namespace
-{
-template <class XmlCfg>
-XmlCfg loadCfgImpl(const wxString& filename, std::unique_ptr<xmlAccess::FfsXmlError>& exeption) //throw xmlAccess::FfsXmlError
-{
- XmlCfg cfg;
- try
- {
- xmlAccess::readConfig(filename, cfg); //throw xmlAccess::FfsXmlError
- }
- catch (const xmlAccess::FfsXmlError& e)
- {
- if (e.getSeverity() == xmlAccess::FfsXmlError::FATAL)
- throw;
- else
- exeption.reset(new xmlAccess::FfsXmlError(e));
- }
- return cfg;
-}
-
-
-template <class XmlCfg>
-void mergeConfigFilesImpl(const std::vector<wxString>& filenames, XmlCfg& config) //throw xmlAccess::FfsXmlError
-{
- using namespace xmlAccess;
-
- assert(!filenames.empty());
- if (filenames.empty())
- return;
-
- std::vector<zen::MainConfiguration> mainCfgs;
- std::unique_ptr<FfsXmlError> savedException;
-
- for (std::vector<wxString>::const_iterator i = filenames.begin(); i != filenames.end(); ++i)
- {
- switch (getXmlType(*i))
- {
- case XML_TYPE_GUI:
- mainCfgs.push_back(loadCfgImpl<XmlGuiConfig>(*i, savedException).mainCfg); //throw xmlAccess::FfsXmlError
- break;
-
- case XML_TYPE_BATCH:
- mainCfgs.push_back(loadCfgImpl<XmlBatchConfig>(*i, savedException).mainCfg); //throw xmlAccess::FfsXmlError
- break;
-
- case XML_TYPE_GLOBAL:
- case XML_TYPE_OTHER:
- break;
- }
- }
-
- if (mainCfgs.empty())
- throw FfsXmlError(_("Invalid FreeFileSync config file!"));
-
- try //...to init all non-"mainCfg" settings with first config file
- {
- xmlAccess::readConfig(filenames[0], config); //throw xmlAccess::FfsXmlError
- }
- catch (xmlAccess::FfsXmlError&) {}
-
- config.mainCfg = merge(mainCfgs);
-
- if (savedException.get()) //"re-throw" exception
- throw* savedException;
-}
-}
-
-
-void xmlAccess::convertConfig(const std::vector<wxString>& filenames, XmlGuiConfig& config) //throw (xmlAccess::FfsXmlError)
-{
- mergeConfigFilesImpl(filenames, config); //throw (xmlAccess::FfsXmlError)
-}
-
-
-void xmlAccess::convertConfig(const std::vector<wxString>& filenames, XmlBatchConfig& config) //throw (xmlAccess::FfsXmlError);
-{
- mergeConfigFilesImpl(filenames, config); //throw (xmlAccess::FfsXmlError)
-}
-
-
-namespace zen
-{
-template <> inline
-void writeText(const CompareVariant& value, std::string& output)
-{
- switch (value)
- {
- case zen::CMP_BY_TIME_SIZE:
- output = "ByTimeAndSize";
- break;
- case zen::CMP_BY_CONTENT:
- output = "ByContent";
- break;
- }
-}
-
-template <> inline
-bool readText(const std::string& input, CompareVariant& value)
-{
- std::string tmp = input;
- zen::trim(tmp);
- if (tmp == "ByTimeAndSize")
- value = zen::CMP_BY_TIME_SIZE;
- else if (tmp == "ByContent")
- value = zen::CMP_BY_CONTENT;
- else
- return false;
- return true;
-}
-
-
-template <> inline
-void writeText(const SyncDirection& value, std::string& output)
-{
- switch (value)
- {
- case SYNC_DIR_LEFT:
- output = "left";
- break;
- case SYNC_DIR_RIGHT:
- output = "right";
- break;
- case SYNC_DIR_NONE:
- output = "none";
- break;
- }
-}
-
-template <> inline
-bool readText(const std::string& input, SyncDirection& value)
-{
- std::string tmp = input;
- zen::trim(tmp);
- if (tmp == "left")
- value = SYNC_DIR_LEFT;
- else if (tmp == "right")
- value = SYNC_DIR_RIGHT;
- else if (tmp == "none")
- value = SYNC_DIR_NONE;
- else
- return false;
- return true;
-}
-
-
-template <> inline
-void writeText(const OnError& value, std::string& output)
-{
- switch (value)
- {
- case ON_ERROR_IGNORE:
- output = "Ignore";
- break;
- case ON_ERROR_EXIT:
- output = "Exit";
- break;
- case ON_ERROR_POPUP:
- output = "Popup";
- break;
- }
-}
-
-template <> inline
-bool readText(const std::string& input, OnError& value)
-{
- std::string tmp = input;
- zen::trim(tmp);
- if (tmp == "Ignore")
- value = ON_ERROR_IGNORE;
- else if (tmp == "Exit")
- value = ON_ERROR_EXIT;
- else if (tmp == "Popup")
- value = ON_ERROR_POPUP;
- else
- return false;
- return true;
-}
-
-
-template <> inline
-void writeText(const OnGuiError& value, std::string& output)
-{
- switch (value)
- {
- case ON_GUIERROR_IGNORE:
- output = "Ignore";
- break;
- case ON_GUIERROR_POPUP:
- output = "Popup";
- break;
- }
-}
-
-template <> inline
-bool readText(const std::string& input, OnGuiError& value)
-{
- std::string tmp = input;
- zen::trim(tmp);
- if (tmp == "Ignore")
- value = ON_GUIERROR_IGNORE;
- else if (tmp == "Popup")
- value = ON_GUIERROR_POPUP;
- else
- return false;
- return true;
-}
-
-
-template <> inline
-void writeText(const FileIconSize& value, std::string& output)
-{
- switch (value)
- {
- case ICON_SIZE_SMALL:
- output = "Small";
- break;
- case ICON_SIZE_MEDIUM:
- output = "Medium";
- break;
- case ICON_SIZE_LARGE:
- output = "Large";
- break;
- }
-}
-
-
-template <> inline
-bool readText(const std::string& input, FileIconSize& value)
-{
- std::string tmp = input;
- zen::trim(tmp);
- if (tmp == "Small")
- value = ICON_SIZE_SMALL;
- else if (tmp == "Medium")
- value = ICON_SIZE_MEDIUM;
- else if (tmp == "Large")
- value = ICON_SIZE_LARGE;
- else
- return false;
- return true;
-}
-
-
-template <> inline
-void writeText(const DeletionPolicy& value, std::string& output)
-{
- switch (value)
- {
- case DELETE_PERMANENTLY:
- output = "DeletePermanently";
- break;
- case MOVE_TO_RECYCLE_BIN:
- output = "MoveToRecycleBin";
- break;
- case MOVE_TO_CUSTOM_DIRECTORY:
- output = "MoveToCustomDirectory";
- break;
- }
-}
-
-template <> inline
-bool readText(const std::string& input, DeletionPolicy& value)
-{
- std::string tmp = input;
- zen::trim(tmp);
- if (tmp == "DeletePermanently")
- value = DELETE_PERMANENTLY;
- else if (tmp == "MoveToRecycleBin")
- value = MOVE_TO_RECYCLE_BIN;
- else if (tmp == "MoveToCustomDirectory")
- value = MOVE_TO_CUSTOM_DIRECTORY;
- else
- return false;
- return true;
-}
-
-
-template <> inline
-void writeText(const SymLinkHandling& value, std::string& output)
-{
- switch (value)
- {
- case SYMLINK_IGNORE:
- output = "Ignore";
- break;
- case SYMLINK_USE_DIRECTLY:
- output = "UseDirectly";
- break;
- case SYMLINK_FOLLOW_LINK:
- output = "FollowLink";
- break;
- }
-}
-
-template <> inline
-bool readText(const std::string& input, SymLinkHandling& value)
-{
- std::string tmp = input;
- zen::trim(tmp);
- if (tmp == "Ignore")
- value = SYMLINK_IGNORE;
- else if (tmp == "UseDirectly")
- value = SYMLINK_USE_DIRECTLY;
- else if (tmp == "FollowLink")
- value = SYMLINK_FOLLOW_LINK;
- else
- return false;
- return true;
-}
-
-
-template <> inline
-void writeText(const UnitTime& value, std::string& output)
-{
- switch (value)
- {
- case UTIME_NONE:
- output = "Inactive";
- break;
- // case UTIME_LAST_X_HOURS:
- // output = "x-hours";
- // break;
- case UTIME_TODAY:
- output = "Today";
- break;
- case UTIME_THIS_WEEK:
- output = "Week";
- break;
- case UTIME_THIS_MONTH:
- output = "Month";
- break;
- case UTIME_THIS_YEAR:
- output = "Year";
- break;
- }
-}
-
-template <> inline
-bool readText(const std::string& input, UnitTime& value)
-{
- std::string tmp = input;
- zen::trim(tmp);
- if (tmp == "Inactive")
- value = UTIME_NONE;
- // else if (tmp == "x-hours")
- // value = UTIME_LAST_X_HOURS;
- else if (tmp == "Today")
- value = UTIME_TODAY;
- else if (tmp == "Week")
- value = UTIME_THIS_WEEK;
- else if (tmp == "Month")
- value = UTIME_THIS_MONTH;
- else if (tmp == "Year")
- value = UTIME_THIS_YEAR;
- else
- return false;
- return true;
-}
-
-
-template <> inline
-void writeText(const ColumnTypes& value, std::string& output)
-{
- output = toString<std::string>(value);
-}
-
-template <> inline
-bool readText(const std::string& input, ColumnTypes& value)
-{
- value = static_cast<ColumnTypes>(toNumber<int>(input));
- return true;
-}
-
-
-template <> inline
-void writeText(const UnitSize& value, std::string& output)
-{
- switch (value)
- {
- case USIZE_NONE:
- output = "Inactive";
- break;
- case USIZE_BYTE:
- output = "Byte";
- break;
- case USIZE_KB:
- output = "KB";
- break;
- case USIZE_MB:
- output = "MB";
- break;
- }
-}
-
-template <> inline
-bool readText(const std::string& input, UnitSize& value)
-{
- std::string tmp = input;
- zen::trim(tmp);
- if (tmp == "Inactive")
- value = USIZE_NONE;
- else if (tmp == "Byte")
- value = USIZE_BYTE;
- else if (tmp == "KB")
- value = USIZE_KB;
- else if (tmp == "MB")
- value = USIZE_MB;
- else
- return false;
- return true;
-}
-
-
-template <> inline
-void writeText(const DirectionConfig::Variant& value, std::string& output)
-{
- switch (value)
- {
- case DirectionConfig::AUTOMATIC:
- output = "Automatic";
- break;
- case DirectionConfig::MIRROR:
- output = "Mirror";
- break;
- case DirectionConfig::UPDATE:
- output = "Update";
- break;
- case DirectionConfig::CUSTOM:
- output = "Custom";
- break;
- }
-}
-
-template <> inline
-bool readText(const std::string& input, DirectionConfig::Variant& value)
-{
- std::string tmp = input;
- zen::trim(tmp);
- if (tmp == "Automatic")
- value = DirectionConfig::AUTOMATIC;
- else if (tmp == "Mirror")
- value = DirectionConfig::MIRROR;
- else if (tmp == "Update")
- value = DirectionConfig::UPDATE;
- else if (tmp == "Custom")
- value = DirectionConfig::CUSTOM;
- else
- return false;
- return true;
-}
-
-
-template <> inline
-bool readValue(const XmlElement& input, ColumnAttrib& value)
-{
- XmlIn in(input);
- bool rv1 = in.attribute("Type", value.type);
- bool rv2 = in.attribute("Visible", value.visible);
- bool rv3 = in.attribute("Width", value.width);
- value.position = 0;
- return rv1 && rv2 && rv3;
-}
-
-template <> inline
-void writeValue(const ColumnAttrib& value, XmlElement& output)
-{
- XmlOut out(output);
- out.attribute("Type", value.type);
- out.attribute("Visible", value.visible);
- out.attribute("Width", value.width);
-}
-}
-
-
-namespace
-{
-void readConfig(const XmlIn& in, CompConfig& cmpConfig)
-{
- in["Variant" ](cmpConfig.compareVar);
- in["HandleSymlinks"](cmpConfig.handleSymlinks);
-}
-
-
-void readConfig(const XmlIn& in, DirectionConfig& directCfg)
-{
- in["Variant"](directCfg.var);
-
- XmlIn inCustDir = in["CustomDirections"];
- inCustDir["LeftOnly" ](directCfg.custom.exLeftSideOnly);
- inCustDir["RightOnly" ](directCfg.custom.exRightSideOnly);
- inCustDir["LeftNewer" ](directCfg.custom.leftNewer);
- inCustDir["RightNewer"](directCfg.custom.rightNewer);
- inCustDir["Different" ](directCfg.custom.different);
- inCustDir["Conflict" ](directCfg.custom.conflict);
-}
-
-
-void readConfig(const XmlIn& in, SyncConfig& syncCfg)
-{
- readConfig(in, syncCfg.directionCfg);
-
- in["DeletionPolicy" ](syncCfg.handleDeletion);
- in["CustomDeletionFolder"](syncCfg.customDeletionDirectory);
-}
-
-
-void readConfig(const XmlIn& in, FilterConfig& filter)
-{
- in["Include"](filter.includeFilter);
- in["Exclude"](filter.excludeFilter);
-
- in["TimeSpan" ](filter.timeSpan);
- in["UnitTimeSpan"](filter.unitTimeSpan);
-
- in["SizeMin" ](filter.sizeMin);
- in["UnitSizeMin"](filter.unitSizeMin);
-
- in["SizeMax" ](filter.sizeMax);
- in["UnitSizeMax"](filter.unitSizeMax);
-}
-
-
-void readConfig(const XmlIn& in, FolderPairEnh& enhPair)
-{
- //read folder pairs
- in["Left" ](enhPair.leftDirectory);
- in["Right"](enhPair.rightDirectory);
-
- //###########################################################
- //alternate comp configuration (optional)
- XmlIn inAltCmp = in["AlternateCompareConfig"];
- if (inAltCmp)
- {
- CompConfig altCmpCfg;
- readConfig(inAltCmp, altCmpCfg);
-
- enhPair.altCmpConfig = std::make_shared<CompConfig>(altCmpCfg);;
- }
- //###########################################################
- //alternate sync configuration (optional)
- XmlIn inAltSync = in["SyncConfig"];
- if (inAltSync)
- {
- SyncConfig altSyncCfg;
- readConfig(inAltSync, altSyncCfg);
-
- enhPair.altSyncConfig = std::make_shared<SyncConfig>(altSyncCfg);
- }
-
- //###########################################################
- //alternate filter configuration
- readConfig(in["LocalFilter"], enhPair.localFilter);
-}
-
-
-void readConfig(const XmlIn& in, MainConfiguration& mainCfg)
-{
- //read compare settings
- XmlIn inCmp = in["MainConfig"]["Comparison"];
-
- readConfig(inCmp, mainCfg.cmpConfig);
- //###########################################################
-
- XmlIn inSync = in["MainConfig"]["SyncConfig"];
-
- //read sync configuration
- readConfig(inSync, mainCfg.syncCfg);
- //###########################################################
-
- XmlIn inFilter = in["MainConfig"]["GlobalFilter"];
- //read filter settings
- readConfig(inFilter, mainCfg.globalFilter);
-
- //###########################################################
- //read all folder pairs
- mainCfg.additionalPairs.clear();
-
- bool firstIter = true;
- for (XmlIn inPair = in["MainConfig"]["FolderPairs"]["Pair"]; inPair; inPair.next())
- {
- FolderPairEnh newPair;
- readConfig(inPair, newPair);
-
- if (firstIter)
- {
- firstIter = false;
- mainCfg.firstPair = newPair; //set first folder pair
- }
- else
- mainCfg.additionalPairs.push_back(newPair); //set additional folder pairs
- }
-}
-
-
-void readConfig(const XmlIn& in, xmlAccess::XmlGuiConfig& config)
-{
- ::readConfig(in, config.mainCfg); //read main config
-
- //read GUI specific config data
- XmlIn inGuiCfg = in["GuiConfig"];
-
- inGuiCfg["HideFiltered" ](config.hideFilteredElements);
- inGuiCfg["HandleError" ](config.handleError);
- inGuiCfg["SyncPreviewActive"](config.syncPreviewEnabled);
-}
-
-
-void readConfig(const XmlIn& in, xmlAccess::XmlBatchConfig& config)
-{
- ::readConfig(in, config.mainCfg); //read main config
-
- //read GUI specific config data
- XmlIn inBatchCfg = in["BatchConfig"];
-
- inBatchCfg["Silent" ](config.silent);
- inBatchCfg["LogfileDirectory"](config.logFileDirectory);
- inBatchCfg["LogfileCountMax" ](config.logFileCountMax);
- inBatchCfg["HandleError" ](config.handleError);
-}
-
-
-void readConfig(const XmlIn& in, XmlGlobalSettings& config)
-{
- XmlIn inShared = in["Shared"];
-
- //try to read program language setting
- inShared["Language"](config.programLanguage);
-
- inShared["CopyLockedFiles" ](config.copyLockedFiles);
- inShared["CopyFilePermissions" ](config.copyFilePermissions);
- inShared["TransactionalFileCopy"](config.transactionalFileCopy);
- inShared["VerifyCopiedFiles" ](config.verifyFileCopy);
-
- //max. allowed file time deviation
- inShared["FileTimeTolerance"](config.fileTimeTolerance);
-
- XmlIn inOpt = inShared["ShowOptionalDialogs"];
- inOpt["CheckForDependentFolders" ](config.optDialogs.warningDependentFolders);
- inOpt["CheckForMultipleWriteAccess" ](config.optDialogs.warningMultiFolderWriteAccess);
- inOpt["CheckForSignificantDifference"](config.optDialogs.warningSignificantDifference);
- inOpt["CheckForFreeDiskSpace"](config.optDialogs.warningNotEnoughDiskSpace);
- inOpt["CheckForUnresolvedConflicts"](config.optDialogs.warningUnresolvedConflicts);
- inOpt["NotifyDatabaseError"](config.optDialogs.warningSyncDatabase);
- inOpt["CheckMissingRecycleBin"](config.optDialogs.warningRecyclerMissing);
- inOpt["PopupOnConfigChange"](config.optDialogs.popupOnConfigChange);
- inOpt["SummaryBeforeSync" ](config.optDialogs.showSummaryBeforeSync);
-
- //gui specific global settings (optional)
- XmlIn inGui = in["Gui"];
- XmlIn inWnd = inGui["Windows"]["Main"];
-
- //read application window size and position
- inWnd["Width" ](config.gui.dlgSize.x);
- inWnd["Height" ](config.gui.dlgSize.y);
- inWnd["PosX" ](config.gui.dlgPos.x);
- inWnd["PosY" ](config.gui.dlgPos.y);
- inWnd["Maximized"](config.gui.isMaximized);
-
- inWnd["MaxFolderPairsVisible"](config.gui.maxFolderPairsVisible);
-
- inWnd["ManualDeletionOnBothSides"](config.gui.deleteOnBothSides);
- inWnd["ManualDeletionUseRecycler"](config.gui.useRecyclerForManualDeletion);
- inWnd["RespectCaseOnSearch" ](config.gui.textSearchRespectCase);
-
- inWnd["IconSize"](config.gui.iconSize);
-
- //###########################################################
- //read column attributes
- XmlIn inColLeft = inWnd["LeftColumns"];
- inColLeft.attribute("AutoAdjust", config.gui.autoAdjustColumnsLeft);
-
- inColLeft(config.gui.columnAttribLeft);
- for (size_t i = 0; i < config.gui.columnAttribLeft.size(); ++i)
- config.gui.columnAttribLeft[i].position = i;
-
- //###########################################################
- XmlIn inColRight = inWnd["RightColumns"];
- inColRight.attribute("AutoAdjust", config.gui.autoAdjustColumnsRight);
-
- inColRight(config.gui.columnAttribRight);
- for (size_t i = 0; i < config.gui.columnAttribRight.size(); ++i)
- config.gui.columnAttribRight[i].position = i;
-
- inWnd["FolderHistoryLeft" ](config.gui.folderHistoryLeft);
- inWnd["FolderHistoryRight"](config.gui.folderHistoryRight);
- inWnd["MaximumHistorySize"](config.gui.folderHistMax);
- inWnd["Perspective" ](config.gui.guiPerspectiveLast);
-
- //external applications
- inGui["ExternalApplications"](config.gui.externelApplications);
-
- //load config file history
- inGui["LastConfigActive"](config.gui.lastUsedConfigFiles);
- inGui["ConfigHistory"](config.gui.cfgFileHistory);
-
- //last update check
- inGui["LastUpdateCheck"](config.gui.lastUpdateCheck);
-
- //batch specific global settings
- //XmlIn inBatch = in["Batch"];
-}
-
-
-template <class ConfigType>
-void readConfig(const wxString& filename, XmlType type, ConfigType& config)
-{
- if (!fileExists(toZ(filename)))
- throw FfsXmlError(wxString(_("File does not exist:")) + wxT("\n\"") + filename + wxT("\""));
-
- XmlDoc doc;
- loadXmlDocument(filename, doc); //throw (FfsXmlError)
-
- if (getXmlType(doc) != type) //throw()
- throw FfsXmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + filename + wxT("\""));
-
- XmlIn in(doc);
- ::readConfig(in, config);
-
- if (in.errorsOccured())
- throw FfsXmlError(wxString(_("Error parsing configuration file:")) + wxT("\n\"") + filename + wxT("\"\n\n") +
- getErrorMessageFormatted(in), FfsXmlError::WARNING);
-}
-}
-
-
-void xmlAccess::readConfig(const wxString& filename, xmlAccess::XmlGuiConfig& config)
-{
- ::readConfig(filename, XML_TYPE_GUI, config);
-}
-
-
-void xmlAccess::readConfig(const wxString& filename, xmlAccess::XmlBatchConfig& config)
-{
- ::readConfig(filename, XML_TYPE_BATCH, config);
-}
-
-
-void xmlAccess::readConfig(xmlAccess::XmlGlobalSettings& config)
-{
- ::readConfig(getGlobalConfigFile(), XML_TYPE_GLOBAL, config);
-}
-
-
-//################################################################################################
-namespace
-{
-void writeConfig(const CompConfig& cmpConfig, XmlOut& out)
-{
- out["Variant" ](cmpConfig.compareVar);
- out["HandleSymlinks"](cmpConfig.handleSymlinks);
-}
-
-
-void writeConfig(const DirectionConfig& directCfg, XmlOut& out)
-{
- out["Variant"](directCfg.var);
-
- XmlOut outCustDir = out["CustomDirections"];
- outCustDir["LeftOnly" ](directCfg.custom.exLeftSideOnly);
- outCustDir["RightOnly" ](directCfg.custom.exRightSideOnly);
- outCustDir["LeftNewer" ](directCfg.custom.leftNewer);
- outCustDir["RightNewer"](directCfg.custom.rightNewer);
- outCustDir["Different" ](directCfg.custom.different);
- outCustDir["Conflict" ](directCfg.custom.conflict);
-}
-
-
-void writeConfig(const SyncConfig& syncCfg, XmlOut& out)
-{
- writeConfig(syncCfg.directionCfg, out);
-
- out["DeletionPolicy" ](syncCfg.handleDeletion);
- out["CustomDeletionFolder"](syncCfg.customDeletionDirectory);
-}
-
-
-void writeConfig(const FilterConfig& filter, XmlOut& out)
-{
- out["Include"](filter.includeFilter);
- out["Exclude"](filter.excludeFilter);
-
- out["TimeSpan" ](filter.timeSpan);
- out["UnitTimeSpan"](filter.unitTimeSpan);
-
- out["SizeMin" ](filter.sizeMin);
- out["UnitSizeMin"](filter.unitSizeMin);
-
- out["SizeMax" ](filter.sizeMax);
- out["UnitSizeMax"](filter.unitSizeMax);
-}
-
-
-void writeConfigFolderPair(const FolderPairEnh& enhPair, XmlOut& out)
-{
- XmlOut outPair = out.ref().addChild("Pair");
-
- //read folder pairs
- outPair["Left" ](enhPair.leftDirectory);
- outPair["Right"](enhPair.rightDirectory);
-
- //###########################################################
- //alternate comp configuration (optional)
- if (enhPair.altCmpConfig.get())
- {
- XmlOut outAlt = outPair["AlternateCompareConfig"];
-
- writeConfig(*enhPair.altCmpConfig, outAlt);
- }
- //###########################################################
- //alternate sync configuration (optional)
- if (enhPair.altSyncConfig.get())
- {
- XmlOut outAltSync = outPair["SyncConfig"];
-
- writeConfig(*enhPair.altSyncConfig, outAltSync);
- }
-
- //###########################################################
- //alternate filter configuration
- XmlOut outFilter = outPair["LocalFilter"];
- writeConfig(enhPair.localFilter, outFilter);
-}
-
-
-void writeConfig(const MainConfiguration& mainCfg, XmlOut& out)
-{
- XmlOut outCmp = out["MainConfig"]["Comparison"];
-
- writeConfig(mainCfg.cmpConfig, outCmp);
- //###########################################################
-
- XmlOut outSync = out["MainConfig"]["SyncConfig"];
-
- writeConfig(mainCfg.syncCfg, outSync);
- //###########################################################
-
- XmlOut outFilter = out["MainConfig"]["GlobalFilter"];
- //write filter settings
- writeConfig(mainCfg.globalFilter, outFilter);
-
- //###########################################################
- //write all folder pairs
-
- XmlOut outFp = out["MainConfig"]["FolderPairs"];
-
- //write first folder pair
- writeConfigFolderPair(mainCfg.firstPair, outFp);
-
- //write additional folder pairs
- std::for_each(mainCfg.additionalPairs.begin(), mainCfg.additionalPairs.end(),
- [&](const FolderPairEnh& fp) { writeConfigFolderPair(fp, outFp); });
-}
-
-
-void writeConfig(const XmlGuiConfig& config, XmlOut& out)
-{
- writeConfig(config.mainCfg, out); //write main config
-
- //write GUI specific config data
- XmlOut outGuiCfg = out["GuiConfig"];
-
- outGuiCfg["HideFiltered" ](config.hideFilteredElements);
- outGuiCfg["HandleError" ](config.handleError);
- outGuiCfg["SyncPreviewActive"](config.syncPreviewEnabled);
-}
-
-void writeConfig(const XmlBatchConfig& config, XmlOut& out)
-{
-
- writeConfig(config.mainCfg, out); //write main config
-
- //write GUI specific config data
- XmlOut outBatchCfg = out["BatchConfig"];
-
- outBatchCfg["Silent" ](config.silent);
- outBatchCfg["LogfileDirectory"](config.logFileDirectory);
- outBatchCfg["LogfileCountMax" ](config.logFileCountMax);
- outBatchCfg["HandleError" ](config.handleError);
-}
-
-
-void writeConfig(const XmlGlobalSettings& config, XmlOut& out)
-{
- XmlOut outShared = out["Shared"];
-
- //write program language setting
- outShared["Language"](config.programLanguage);
-
- outShared["CopyLockedFiles" ](config.copyLockedFiles);
- outShared["CopyFilePermissions" ](config.copyFilePermissions);
- outShared["TransactionalFileCopy"](config.transactionalFileCopy);
- outShared["VerifyCopiedFiles" ](config.verifyFileCopy);
-
- //max. allowed file time deviation
- outShared["FileTimeTolerance"](config.fileTimeTolerance);
-
- XmlOut outOpt = outShared["ShowOptionalDialogs"];
- outOpt["CheckForDependentFolders" ](config.optDialogs.warningDependentFolders);
- outOpt["CheckForMultipleWriteAccess" ](config.optDialogs.warningMultiFolderWriteAccess);
- outOpt["CheckForSignificantDifference"](config.optDialogs.warningSignificantDifference);
- outOpt["CheckForFreeDiskSpace"](config.optDialogs.warningNotEnoughDiskSpace);
- outOpt["CheckForUnresolvedConflicts"](config.optDialogs.warningUnresolvedConflicts);
- outOpt["NotifyDatabaseError"](config.optDialogs.warningSyncDatabase);
- outOpt["CheckMissingRecycleBin"](config.optDialogs.warningRecyclerMissing);
- outOpt["PopupOnConfigChange"](config.optDialogs.popupOnConfigChange);
- outOpt["SummaryBeforeSync" ](config.optDialogs.showSummaryBeforeSync);
-
- //gui specific global settings (optional)
- XmlOut outGui = out["Gui"];
- XmlOut outWnd = outGui["Windows"]["Main"];
-
- //write application window size and position
- outWnd["Width" ](config.gui.dlgSize.x);
- outWnd["Height" ](config.gui.dlgSize.y);
- outWnd["PosX" ](config.gui.dlgPos.x);
- outWnd["PosY" ](config.gui.dlgPos.y);
- outWnd["Maximized"](config.gui.isMaximized);
-
- outWnd["MaxFolderPairsVisible"](config.gui.maxFolderPairsVisible);
-
- outWnd["ManualDeletionOnBothSides"](config.gui.deleteOnBothSides);
- outWnd["ManualDeletionUseRecycler"](config.gui.useRecyclerForManualDeletion);
- outWnd["RespectCaseOnSearch" ](config.gui.textSearchRespectCase);
-
- outWnd["IconSize"](config.gui.iconSize);
-
- //###########################################################
-
- //write column attributes
- XmlOut outColLeft = outWnd["LeftColumns"];
- outColLeft.attribute("AutoAdjust", config.gui.autoAdjustColumnsLeft);
-
- outColLeft(config.gui.columnAttribLeft);
-
- //###########################################################
- XmlOut outColRight = outWnd["RightColumns"];
- outColRight.attribute("AutoAdjust", config.gui.autoAdjustColumnsRight);
-
- outColRight(config.gui.columnAttribRight);
-
- outWnd["FolderHistoryLeft" ](config.gui.folderHistoryLeft);
- outWnd["FolderHistoryRight"](config.gui.folderHistoryRight);
- outWnd["MaximumHistorySize"](config.gui.folderHistMax);
- outWnd["Perspective" ](config.gui.guiPerspectiveLast);
-
- //external applications
- outGui["ExternalApplications"](config.gui.externelApplications);
-
- //load config file history
- outGui["LastConfigActive"](config.gui.lastUsedConfigFiles);
- outGui["ConfigHistory"](config.gui.cfgFileHistory);
-
- //last update check
- outGui["LastUpdateCheck"](config.gui.lastUpdateCheck);
-
- //batch specific global settings
- //XmlOut outBatch = out["Batch"];
-}
-
-
-template <class ConfigType>
-void writeConfig(const ConfigType& config, XmlType type, const wxString& filename)
-{
- XmlDoc doc("FreeFileSync");
- setXmlType(doc, type); //throw()
-
- XmlOut out(doc);
- writeConfig(config, out);
-
- saveXmlDocument(doc, filename); //throw (FfsXmlError)
-}
-}
-
-void xmlAccess::writeConfig(const XmlGuiConfig& config, const wxString& filename)
-{
- ::writeConfig(config, XML_TYPE_GUI, filename); //throw (FfsXmlError)
-}
-
-
-void xmlAccess::writeConfig(const XmlBatchConfig& config, const wxString& filename)
-{
- ::writeConfig(config, XML_TYPE_BATCH, filename); //throw (FfsXmlError)
-}
-
-
-void xmlAccess::writeConfig(const XmlGlobalSettings& config)
-{
- ::writeConfig(config, XML_TYPE_GLOBAL, getGlobalConfigFile()); //throw (FfsXmlError)
-}
diff --git a/library/process_xml.h b/library/process_xml.h
deleted file mode 100644
index 851b0d9c..00000000
--- a/library/process_xml.h
+++ /dev/null
@@ -1,283 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#ifndef PROCESSXML_H_INCLUDED
-#define PROCESSXML_H_INCLUDED
-
-#include <wx/gdicmn.h>
-#include "../structures.h"
-#include "../shared/xml_error.h"
-#include "../shared/localization.h"
-
-namespace xmlAccess
-{
-enum XmlType
-{
- XML_TYPE_GUI,
- XML_TYPE_BATCH,
- XML_TYPE_GLOBAL,
- XML_TYPE_OTHER
-};
-
-XmlType getXmlType(const wxString& filename); //throw()
-
-
-enum OnError
-{
- ON_ERROR_POPUP,
- ON_ERROR_IGNORE,
- ON_ERROR_EXIT
-};
-
-enum OnGuiError
-{
- ON_GUIERROR_POPUP,
- ON_GUIERROR_IGNORE
-};
-
-enum ColumnTypes
-{
- DIRECTORY, //this needs to begin with 0 and be continuous (some code relies on it)
- FULL_PATH,
- REL_PATH,
- FILENAME,
- SIZE,
- DATE,
- EXTENSION
-};
-const size_t COLUMN_TYPE_COUNT = 7;
-
-struct ColumnAttrib
-{
- ColumnTypes type;
- bool visible;
- size_t position;
- int width;
-};
-typedef std::vector<ColumnAttrib> ColumnAttributes;
-
-
-typedef wxString Description;
-typedef wxString Commandline;
-typedef std::vector<std::pair<Description, Commandline> > ExternalApps;
-
-//---------------------------------------------------------------------
-struct XmlGuiConfig
-{
- XmlGuiConfig() :
- hideFilteredElements(false),
- handleError(ON_GUIERROR_POPUP),
- syncPreviewEnabled(true) {} //initialize values
-
- zen::MainConfiguration mainCfg;
-
- bool hideFilteredElements;
- OnGuiError handleError; //reaction on error situation during synchronization
- bool syncPreviewEnabled;
-
- bool operator==(const XmlGuiConfig& other) const
- {
- return mainCfg == other.mainCfg &&
- hideFilteredElements == other.hideFilteredElements &&
- handleError == other.handleError &&
- syncPreviewEnabled == other.syncPreviewEnabled;
- }
-
- bool operator!=(const XmlGuiConfig& other) const { return !(*this == other); }
-};
-
-
-struct XmlBatchConfig
-{
- XmlBatchConfig() :
- silent(false),
- logFileCountMax(200),
- handleError(ON_ERROR_POPUP) {}
-
- zen::MainConfiguration mainCfg;
-
- bool silent;
- wxString logFileDirectory;
- size_t logFileCountMax;
- OnError handleError; //reaction on error situation during synchronization
-};
-
-
-struct OptionalDialogs
-{
- OptionalDialogs() { resetDialogs();}
-
- void resetDialogs();
-
- bool warningDependentFolders;
- bool warningMultiFolderWriteAccess;
- bool warningSignificantDifference;
- bool warningNotEnoughDiskSpace;
- bool warningUnresolvedConflicts;
- bool warningSyncDatabase;
- bool warningRecyclerMissing;
- bool popupOnConfigChange;
- bool showSummaryBeforeSync;
-};
-
-
-enum FileIconSize
-{
- ICON_SIZE_SMALL,
- ICON_SIZE_MEDIUM,
- ICON_SIZE_LARGE
-};
-
-
-wxString getGlobalConfigFile();
-
-struct XmlGlobalSettings
-{
- //---------------------------------------------------------------------
- //Shared (GUI/BATCH) settings
- XmlGlobalSettings() :
- programLanguage(zen::retrieveSystemLanguage()),
- copyLockedFiles(true),
- copyFilePermissions(false),
- fileTimeTolerance(2), //default 2s: FAT vs NTFS
- verifyFileCopy(false),
- transactionalFileCopy(true) {}
-
- int programLanguage;
- bool copyLockedFiles; //VSS usage
- bool copyFilePermissions;
-
- size_t fileTimeTolerance; //max. allowed file time deviation
- bool verifyFileCopy; //verify copied files
- bool transactionalFileCopy;
-
- OptionalDialogs optDialogs;
-
- //---------------------------------------------------------------------
- struct _Gui
- {
- _Gui() :
- dlgPos(wxDefaultCoord, wxDefaultCoord),
- dlgSize(wxDefaultCoord, wxDefaultCoord),
- isMaximized(false),
- maxFolderPairsVisible(6),
- autoAdjustColumnsLeft(false),
- autoAdjustColumnsRight(false),
- folderHistMax(15),
- deleteOnBothSides(false),
- useRecyclerForManualDeletion(true), //enable if OS supports it; else user will have to activate first and then get an error message
-#ifdef FFS_WIN
- textSearchRespectCase(false),
-#elif defined FFS_LINUX
- textSearchRespectCase(true),
-#endif
- iconSize(ICON_SIZE_MEDIUM),
- lastUpdateCheck(0)
- {
- //default external apps will be translated "on the fly"!!!
-#ifdef FFS_WIN
- externelApplications.push_back(std::make_pair(wxT("Show in Explorer"), //mark for extraction: _("Show in Explorer")
- wxT("explorer /select, \"%name\"")));
- externelApplications.push_back(std::make_pair(wxT("Open with default application"), //mark for extraction: _("Open with default application")
- wxT("\"%name\"")));
-#elif defined FFS_LINUX
- externelApplications.push_back(std::make_pair(wxT("Browse directory"), //mark for extraction: _("Browse directory")
- wxT("xdg-open \"%dir\"")));
- externelApplications.push_back(std::make_pair(wxT("Open with default application"), //mark for extraction: _("Open with default application")
- wxT("xdg-open \"%name\"")));
-#endif
- }
-
- wxPoint dlgPos;
- wxSize dlgSize;
- bool isMaximized;
-
- int maxFolderPairsVisible;
-
- ColumnAttributes columnAttribLeft;
- ColumnAttributes columnAttribRight;
-
- bool autoAdjustColumnsLeft;
- bool autoAdjustColumnsRight;
-
- ExternalApps externelApplications;
-
- std::vector<wxString> cfgFileHistory;
- std::vector<wxString> lastUsedConfigFiles;
-
- std::vector<Zstring> folderHistoryLeft;
- std::vector<Zstring> folderHistoryRight;
- unsigned int folderHistMax;
-
- bool deleteOnBothSides;
- bool useRecyclerForManualDeletion;
- bool textSearchRespectCase;
-
- FileIconSize iconSize;
-
- long lastUpdateCheck; //time of last update check
-
- wxString guiPerspectiveLast; //used by wxAuiManager
- } gui;
-
- //---------------------------------------------------------------------
- //struct _Batch
-};
-
-
-inline
-bool sortByType(const ColumnAttrib& a, const ColumnAttrib& b)
-{
- return a.type < b.type;
-}
-
-
-inline
-bool sortByPositionOnly(const ColumnAttrib& a, const ColumnAttrib& b)
-{
- return a.position < b.position;
-}
-
-
-inline
-bool sortByPositionAndVisibility(const ColumnAttrib& a, const ColumnAttrib& b)
-{
- if (a.visible == false) //hidden elements shall appear at end of vector
- return false;
- if (b.visible == false)
- return true;
- return a.position < b.position;
-}
-
-void readConfig(const wxString& filename, XmlGuiConfig& config); //throw xmlAccess::FfsXmlError
-void readConfig(const wxString& filename, XmlBatchConfig& config); //throw xmlAccess::FfsXmlError
-void readConfig( XmlGlobalSettings& config); //throw xmlAccess::FfsXmlError
-
-void writeConfig(const XmlGuiConfig& config, const wxString& filename); //throw xmlAccess::FfsXmlError
-void writeConfig(const XmlBatchConfig& config, const wxString& filename); //throw xmlAccess::FfsXmlError
-void writeConfig(const XmlGlobalSettings& config); //throw xmlAccess::FfsXmlError
-
-//config conversion utilities
-XmlGuiConfig convertBatchToGui(const XmlBatchConfig& batchCfg);
-XmlBatchConfig convertGuiToBatch(const XmlGuiConfig& guiCfg, const wxString& referenceFile);
-
-
-//convert (multiple) *.ffs_gui, *.ffs_batch files or combinations of both into target config structure:
-enum MergeType
-{
- MERGE_GUI, //pure gui config files
- MERGE_BATCH, // " batch "
- MERGE_GUI_BATCH, //gui and batch files
- MERGE_OTHER
-};
-MergeType getMergeType(const std::vector<wxString>& filenames); //throw ()
-
-void convertConfig(const std::vector<wxString>& filenames, XmlGuiConfig& config); //throw xmlAccess::FfsXmlError
-void convertConfig(const std::vector<wxString>& filenames, XmlBatchConfig& config); //throw xmlAccess::FfsXmlError
-}
-
-
-#endif // PROCESSXML_H_INCLUDED
diff --git a/library/resources.cpp b/library/resources.cpp
deleted file mode 100644
index d8dacc06..00000000
--- a/library/resources.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#include "resources.h"
-#include <wx/wfstream.h>
-#include <wx/zipstrm.h>
-#include <wx/image.h>
-#include <wx/icon.h>
-#include <wx/mstream.h>
-#include "../shared/string_conv.h"
-#include <memory>
-#include "../shared/standard_paths.h"
-
-using namespace zen;
-
-
-const GlobalResources& GlobalResources::instance()
-{
- static GlobalResources inst;
- return inst;
-}
-
-
-namespace
-{
-void loadAnimFromZip(wxZipInputStream& zipInput, wxAnimation* animation)
-{
- //Workaround for wxWidgets:
- //construct seekable input stream (zip-input stream is non-seekable) for wxAnimation::Load()
- //luckily this method call is very fast: below measurement precision!
- std::vector<char> data;
- data.reserve(10000);
-
- int newValue = 0;
- while ((newValue = zipInput.GetC()) != wxEOF)
- data.push_back(newValue);
-
- wxMemoryInputStream seekAbleStream(&data.front(), data.size()); //stream does not take ownership of data
-
- animation->Load(seekAbleStream, wxANIMATION_TYPE_GIF);
-}
-}
-
-
-GlobalResources::GlobalResources()
-{
- //init all the other resource files
- animationMoney = new wxAnimation(wxNullAnimation);
- animationSync = new wxAnimation(wxNullAnimation);
- programIcon = new wxIcon(wxNullIcon);
-
- wxFFileInputStream input(zen::getResourceDir() + wxT("Resources.zip"));
- if (input.IsOk()) //if not... we don't want to react too harsh here
- {
- //activate support for .png files
- wxImage::AddHandler(new wxPNGHandler); //ownership passed
-
- wxZipInputStream resourceFile(input);
-
- while (true)
- {
- std::unique_ptr<wxZipEntry> entry(resourceFile.GetNextEntry());
- if (entry.get() == NULL)
- break;
-
- const wxString name = entry->GetName();
-
- //generic image loading
- if (name.EndsWith(wxT(".png")))
- {
- if (bitmapResource.find(name) == bitmapResource.end()) //avoid duplicate entry: prevent memory leak!
- bitmapResource[name] = new wxBitmap(wxImage(resourceFile, wxBITMAP_TYPE_PNG));
- }
- else if (name == wxT("money.gif"))
- loadAnimFromZip(resourceFile, animationMoney);
- else if (name == wxT("working.gif"))
- loadAnimFromZip(resourceFile, animationSync);
- }
- }
-
-#ifdef FFS_WIN
- //for compatibility it seems we need to stick with a "real" icon
- *programIcon = wxIcon(wxT("A_PROGRAM_ICON"));
-#else
- //use big logo bitmap for better quality
- programIcon->CopyFromBitmap(getImageInt(wxT("FreeFileSync.png")));
- //attention: this is the reason we need a member getImage -> it must not implicitly create static object instance!!!
- //erroneously calling static object constructor twice will deadlock on Linux!!
-#endif
-}
-
-
-GlobalResources::~GlobalResources()
-{
- //free bitmap resources
- for (std::map<wxString, wxBitmap*>::iterator i = bitmapResource.begin(); i != bitmapResource.end(); ++i)
- delete i->second;
-
- //free other resources
- delete animationMoney;
- delete animationSync;
- delete programIcon;
-}
-
-
-const wxBitmap& GlobalResources::getImageInt(const wxString& imageName) const
-{
- const std::map<wxString, wxBitmap*>::const_iterator bmp = bitmapResource.find(
- imageName.Find(L'.') == wxNOT_FOUND ? //assume .png ending if nothing else specified
- imageName + wxT(".png") :
- imageName);
- if (bmp != bitmapResource.end())
- return *bmp->second;
- else
- {
- assert(false);
- return wxNullBitmap;
- }
-}
diff --git a/library/resources.h b/library/resources.h
deleted file mode 100644
index e985d9bf..00000000
--- a/library/resources.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#ifndef RESOURCES_H_INCLUDED
-#define RESOURCES_H_INCLUDED
-
-#include <wx/bitmap.h>
-#include <wx/animate.h>
-#include <wx/string.h>
-#include <map>
-
-
-class GlobalResources
-{
-public:
- static const wxBitmap& getImage(const wxString& name)
- {
- const GlobalResources& inst = instance();
- return inst.getImageInt(name);
- }
-
- static const GlobalResources& instance();
-
- //global image resource objects
- wxAnimation* animationMoney;
- wxAnimation* animationSync;
- wxIcon* programIcon;
-
-private:
- GlobalResources();
- ~GlobalResources();
- GlobalResources(const GlobalResources&);
- GlobalResources& operator=(const GlobalResources&);
-
- const wxBitmap& getImageInt(const wxString& name) const;
-
-
- //resource mapping
- std::map<wxString, wxBitmap*> bitmapResource;
-};
-
-#endif // RESOURCES_H_INCLUDED
diff --git a/library/soft_filter.h b/library/soft_filter.h
deleted file mode 100644
index f3c1bd41..00000000
--- a/library/soft_filter.h
+++ /dev/null
@@ -1,121 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#ifndef SOFT_FILTER_H_INCLUDED
-#define SOFT_FILTER_H_INCLUDED
-
-#include <algorithm>
-#include <limits>
-#include "../structures.h"
-#include <wx/stopwatch.h>
-
-namespace zen
-{
-/*
-Semantics of SoftFilter:
-1. It potentially may match only one side => it MUST NOT be applied while traversing a single folder to avoid mismatches
-2. => it is applied after traversing and just marks rows, (NO deletions after comparison are allowed)
-3. => equivalent to a user temporarily (de-)selecting rows -> not relevant for <Automatic>-mode! ;)
-*/
-
-class SoftFilter
-{
-public:
- SoftFilter(size_t timeSpan, UnitTime unitTimeSpan,
- size_t sizeMin, UnitSize unitSizeMin,
- size_t sizeMax, UnitSize unitSizeMax);
-
- bool matchTime(Int64 writeTime) const { return timeFrom_ <= writeTime; }
- bool matchSize(UInt64 fileSize) const { return sizeMin_ <= fileSize && fileSize <= sizeMax_; }
- bool matchFolder() const { return timeFrom_ == std::numeric_limits<Int64>::min(); }
- //if date filter is active we deactivate all folders: effectively gets rid of empty folders!
-
- bool isNull() const; //filter is equivalent to NullFilter, but may be technically slower
-
- //small helper method: merge two soft filters
- friend SoftFilter combineFilters(const SoftFilter& first, const SoftFilter& second);
-
-private:
- SoftFilter(const Int64& timeFrom,
- const UInt64& sizeMin,
- const UInt64& sizeMax);
-
- Int64 timeFrom_; //unit: UTC, seconds
- UInt64 sizeMin_; //unit: bytes
- UInt64 sizeMax_; //unit: bytes
-};
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-// ----------------------- implementation -----------------------
-namespace zen
-{
-inline
-SoftFilter::SoftFilter(size_t timeSpan, UnitTime unitTimeSpan,
- size_t sizeMin, UnitSize unitSizeMin,
- size_t sizeMax, UnitSize unitSizeMax)
-{
- resolveUnits(timeSpan, unitTimeSpan,
- sizeMin, unitSizeMin,
- sizeMax, unitSizeMax,
- timeFrom_,
- sizeMin_,
- sizeMax_);
-}
-
-inline
-SoftFilter::SoftFilter(const Int64& timeFrom,
- const UInt64& sizeMin,
- const UInt64& sizeMax) :
- timeFrom_(timeFrom),
- sizeMin_ (sizeMin),
- sizeMax_ (sizeMax) {}
-
-inline
-SoftFilter combineFilters(const SoftFilter& first, const SoftFilter& second)
-{
- return SoftFilter(std::max(first.timeFrom_, second.timeFrom_),
- std::max(first.sizeMin_, second.sizeMin_),
- std::min(first.sizeMax_, second.sizeMax_));
-}
-
-inline
-bool SoftFilter::isNull() const //filter is equivalent to NullFilter, but may be technically slower
-{
- return timeFrom_ == std::numeric_limits<Int64>::min() &&
- sizeMin_ == 0U &&
- sizeMax_ == std::numeric_limits<UInt64>::max();
-}
-}
-
-#endif // SOFT_FILTER_H_INCLUDED
diff --git a/library/statistics.cpp b/library/statistics.cpp
deleted file mode 100644
index f6ec01ad..00000000
--- a/library/statistics.cpp
+++ /dev/null
@@ -1,378 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#include "statistics.h"
-
-#include <wx/ffile.h>
-#include "../shared/global_func.h"
-#include "status_handler.h"
-#include "../shared/util.h"
-#include "../shared/i18n.h"
-#include <limits>
-#include <wx/stopwatch.h>
-#include "../shared/assert_static.h"
-
-
-using namespace zen;
-
-RetrieveStatistics::RetrieveStatistics() :
- timer(new wxStopWatch) {}
-
-
-RetrieveStatistics::~RetrieveStatistics()
-{
- //write statistics to a file
- wxFFile outputFile(wxT("statistics.dat"), wxT("w"));
-
- outputFile.Write(wxT("Time(ms);Objects;Data\n"));
-
- for (std::vector<StatEntry>::const_iterator i = data.begin(); i != data.end(); ++i)
- {
- outputFile.Write(toString<wxString>(i->time));
- outputFile.Write(wxT(";"));
- outputFile.Write(toString<wxString>(i->objects));
- outputFile.Write(wxT(";"));
- outputFile.Write(toString<wxString>(i->value));
- outputFile.Write(wxT("\n"));
- }
-}
-
-
-void RetrieveStatistics::writeEntry(const double value, const int objects)
-{
- StatEntry newEntry;
- newEntry.value = value;
- newEntry.objects = objects;
- newEntry.time = timer->Time();
- data.push_back(newEntry);
-}
-
-
-//########################################################################################
-namespace
-{
-template <class T>
-inline
-bool isNull(T number)
-{
- return common::abs(number) <= std::numeric_limits<T>::epsilon(); //epsilon == 0 for integer types, therefore less-equal(!)
-}
-}
-
-
-enum UnitRemTime
-{
- URT_SEC,
- URT_MIN,
- URT_HOUR,
- URT_DAY
-};
-
-
-inline
-wxString Statistics::formatRemainingTime(double timeInMs) const
-{
- double remainingTime = timeInMs / 1000;
-
- //determine preferred unit
- UnitRemTime unit = URT_SEC;
- if (remainingTime > 55)
- {
- unit = URT_MIN;
- remainingTime /= 60;
- if (remainingTime > 59)
- {
- unit = URT_HOUR;
- remainingTime /= 60;
- if (remainingTime > 23)
- {
- unit = URT_DAY;
- remainingTime /= 24;
- }
- }
- }
-
- int formattedTime = common::round(remainingTime);
-
- //reduce precision to 5 seconds
- if (unit == URT_SEC && formattedTime % 5 != 0)
- formattedTime += 5 - formattedTime % 5; //"ceiling"
-
-
- //avoid "jumping back and forth" when fluctuating around .5
- if (remainingTimeLast < formattedTime)
- {
- if (unit == URT_SEC)
- {
- formattedTime = common::round(remainingTime);
- formattedTime -= formattedTime % 5; //"floor"
- }
- else
- formattedTime = static_cast<int>(remainingTime); //"floor"
- }
- remainingTimeLast = formattedTime;
-
- //generate output message
- wxString output;
- switch (unit)
- {
- case URT_SEC:
- output = _P("1 sec", "%x sec", formattedTime);
- break;
- case URT_MIN:
- output = _P("1 min", "%x min", formattedTime);
- break;
- case URT_HOUR:
- output = _P("1 hour", "%x hours", formattedTime);
- break;
- case URT_DAY:
- output = _P("1 day", "%x days", formattedTime);
- break;
- }
- output.Replace(wxT("%x"), zen::toStringSep(formattedTime));
- return output;
-}
-
-
-Statistics::Statistics(int totalObjectCount,
- double totalDataAmount,
- unsigned windowSizeRemainingTime,
- unsigned windowSizeBytesPerSecond) :
- objectsTotal(totalObjectCount),
- dataTotal(totalDataAmount),
- windowSizeRemTime(windowSizeRemainingTime),
- windowSizeBPS(windowSizeBytesPerSecond),
- windowMax(std::max(windowSizeRemainingTime, windowSizeBytesPerSecond)),
- remainingTimeLast(std::numeric_limits<int>::max()), //something "big"
- timer(new wxStopWatch) {}
-
-Statistics::~Statistics()
-{
- delete timer;
-}
-
-void Statistics::addMeasurement(int objectsCurrent, double dataCurrent)
-{
- Record newRecord;
- newRecord.objects = objectsCurrent;
- newRecord.data = dataCurrent;
-
- const long currentTime = timer->Time();
-
- const TimeRecordMap::value_type newEntry(currentTime, newRecord);
-
- //insert new record
- if (!measurements.empty())
- {
- //assert(dataCurrent >= (--measurements.end())->second.data);
- measurements.insert(--measurements.end(), newEntry); //use fact that time is monotonously ascending
- }
- else
- measurements.insert(newEntry);
-
- //remove all records earlier than "currentTime - windowSize"
- const long newBegin = currentTime - windowMax;
- TimeRecordMap::iterator windowBegin = measurements.upper_bound(newBegin);
- if (windowBegin != measurements.begin())
- measurements.erase(measurements.begin(), --windowBegin); //retain one point before newBegin in order to handle "measurement holes"
-}
-
-
-wxString Statistics::getRemainingTime() const
-{
- if (!measurements.empty())
- {
- const TimeRecordMap::value_type& backRecord = *measurements.rbegin();
- //find start of records "window"
- const long frontTime = backRecord.first - windowSizeRemTime;
- TimeRecordMap::const_iterator windowBegin = measurements.upper_bound(frontTime);
- if (windowBegin != measurements.begin())
- --windowBegin; //one point before window begin in order to handle "measurement holes"
-
- const TimeRecordMap::value_type& frontRecord = *windowBegin;
- //-----------------------------------------------------------------------------------------------
- const double timeDelta = backRecord.first - frontRecord.first;
- const double dataDelta = backRecord.second.data - frontRecord.second.data;
-
- const double dataRemaining = dataTotal - backRecord.second.data;
-
- if (!isNull(dataDelta))
- return formatRemainingTime(dataRemaining * timeDelta / dataDelta);
- }
-
- return wxT("-"); //fallback
-}
-
-
-wxString Statistics::getBytesPerSecond() const
-{
- if (!measurements.empty())
- {
- const TimeRecordMap::value_type& backRecord = *measurements.rbegin();
- //find start of records "window"
- const long frontTime = backRecord.first - windowSizeBPS;
- TimeRecordMap::const_iterator windowBegin = measurements.upper_bound(frontTime);
- if (windowBegin != measurements.begin())
- --windowBegin; //one point before window begin in order to handle "measurement holes"
-
- const TimeRecordMap::value_type& frontRecord = *windowBegin;
- //-----------------------------------------------------------------------------------------------
- const double timeDelta = backRecord.first - frontRecord.first;
- const double dataDelta = backRecord.second.data - frontRecord.second.data;
-
- if (!isNull(timeDelta))
- if (dataDelta > 0) //may be negative if user cancels copying
- return zen::formatFilesizeToShortString(zen::UInt64(dataDelta * 1000 / timeDelta)) + _("/sec");
- }
-
- return wxT("-"); //fallback
-}
-
-
-void Statistics::pauseTimer()
-{
- timer->Pause();
-}
-
-
-void Statistics::resumeTimer()
-{
- timer->Resume();
-}
-
-/*
-class for calculation of remaining time:
-----------------------------------------
-"filesize |-> time" is an affine linear function f(x) = z_1 + z_2 x
-
-For given n measurements, sizes x_0, ..., x_n and times f_0, ..., f_n, the function f (as a polynom of degree 1) can be lineary approximated by
-
-z_1 = (r - s * q / p) / ((n + 1) - s * s / p)
-z_2 = (q - s * z_1) / p = (r - (n + 1) z_1) / s
-
-with
-p := x_0^2 + ... + x_n^2
-q := f_0 x_0 + ... + f_n x_n
-r := f_0 + ... + f_n
-s := x_0 + ... + x_n
-
-=> the time to process N files with amount of data D is: N * z_1 + D * z_2
-
-Problem:
---------
-Times f_0, ..., f_n can be very small so that precision of the PC clock is poor.
-=> Times have to be accumulated to enhance precision:
-Copying of m files with sizes x_i and times f_i (i = 1, ..., m) takes sum_i f(x_i) := m * z_1 + z_2 * sum x_i = sum f_i
-With X defined as the accumulated sizes and F the accumulated times this gives: (in theory...)
-m * z_1 + z_2 * X = F <=>
-z_1 + z_2 * X / m = F / m
-
-=> we obtain a new (artificial) measurement with size X / m and time F / m to be used in the linear approximation above
-
-
-Statistics::Statistics(const int totalObjectCount, const double totalDataAmount, const unsigned recordCount) :
- objectsTotal(totalObjectCount),
- dataTotal(totalDataAmount),
- recordsMax(recordCount),
- objectsLast(0),
- dataLast(0),
- timeLast(wxGetLocalTimeMillis()),
- z1_current(0),
- z2_current(0),
- dummyRecordPresent(false) {}
-
-
-wxString Statistics::getRemainingTime(const int objectsCurrent, const double dataCurrent)
-{
- //add new measurement point
- const int m = objectsCurrent - objectsLast;
- if (m != 0)
- {
- objectsLast = objectsCurrent;
-
- const double X = dataCurrent - dataLast;
- dataLast = dataCurrent;
-
- const zen::Int64 timeCurrent = wxGetLocalTimeMillis();
- const double F = (timeCurrent - timeLast).ToDouble();
- timeLast = timeCurrent;
-
- record newEntry;
- newEntry.x_i = X / m;
- newEntry.f_i = F / m;
-
- //remove dummy record
- if (dummyRecordPresent)
- {
- measurements.pop_back();
- dummyRecordPresent = false;
- }
-
- //insert new record
- measurements.push_back(newEntry);
- if (measurements.size() > recordsMax)
- measurements.pop_front();
- }
- else //dataCurrent increased without processing new objects:
- { //modify last measurement until m != 0
- const double X = dataCurrent - dataLast; //do not set dataLast, timeLast variables here, but write dummy record instead
- if (!isNull(X))
- {
- const zen::Int64 timeCurrent = wxGetLocalTimeMillis();
- const double F = (timeCurrent - timeLast).ToDouble();
-
- record modifyEntry;
- modifyEntry.x_i = X;
- modifyEntry.f_i = F;
-
- //insert dummy record
- if (!dummyRecordPresent)
- {
- measurements.push_back(modifyEntry);
- if (measurements.size() > recordsMax)
- measurements.pop_front();
- dummyRecordPresent = true;
- }
- else //modify dummy record
- measurements.back() = modifyEntry;
- }
- }
-
- //calculate remaining time based on stored measurement points
- double p = 0;
- double q = 0;
- double r = 0;
- double s = 0;
- for (std::list<record>::const_iterator i = measurements.begin(); i != measurements.end(); ++i)
- {
- const double x_i = i->x_i;
- const double f_i = i->f_i;
- p += x_i * x_i;
- q += f_i * x_i;
- r += f_i;
- s += x_i;
- }
-
- if (!isNull(p))
- {
- const double n = measurements.size();
- const double tmp = (n - s * s / p);
-
- if (!isNull(tmp) && !isNull(s))
- {
- const double z1 = (r - s * q / p) / tmp;
- const double z2 = (r - n * z1) / s; //not (n + 1) here, since n already is the number of measurements
-
- //refresh current values for z1, z2
- z1_current = z1;
- z2_current = z2;
- }
- }
-
- return formatRemainingTime((objectsTotal - objectsCurrent) * z1_current + (dataTotal - dataCurrent) * z2_current);
-}
-
-*/
diff --git a/library/statistics.h b/library/statistics.h
deleted file mode 100644
index cfa3e07c..00000000
--- a/library/statistics.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#ifndef STATISTICS_H_INCLUDED
-#define STATISTICS_H_INCLUDED
-
-#include <vector>
-#include <map>
-#include <memory>
-#include <wx/defs.h>
-
-
-#include <wx/string.h>
-
-class wxStopWatch;
-
-
-class RetrieveStatistics
-{
-public:
- wxDEPRECATED( RetrieveStatistics() ); //generate compiler warnings as a reminder to remove code after measurements
- ~RetrieveStatistics();
-
- void writeEntry(const double value, const int objects);
-
-private:
- struct StatEntry
- {
- long time;
- int objects;
- double value;
- };
-
- std::vector<StatEntry> data;
- std::unique_ptr<wxStopWatch> timer;
-};
-
-
-class Statistics
-{
-public:
- Statistics(int totalObjectCount,
- double totalDataAmount,
- unsigned windowSizeRemainingTime, //time in ms
- unsigned windowSizeBytesPerSecond); //time in ms
-
- ~Statistics();
-
- void addMeasurement(int objectsCurrent, double dataCurrent);
- wxString getRemainingTime() const; //returns the remaining time in milliseconds
- wxString getBytesPerSecond() const;
-
- void pauseTimer();
- void resumeTimer();
-
-private:
- wxString formatRemainingTime(double timeInMs) const;
-
- const int objectsTotal;
- const double dataTotal;
-
- const unsigned windowSizeRemTime; //"window width" of statistics used for calculation of remaining time in ms
- const unsigned windowSizeBPS; //
- const unsigned windowMax;
-
- mutable int remainingTimeLast; //used for "smoothening" remaining time
-
- struct Record
- {
- int objects; //object count
- double data; //unit: bytes
- };
-
- typedef std::multimap<long, Record> TimeRecordMap; //time, unit: milliseconds
- TimeRecordMap measurements; //
-
- wxStopWatch* timer;
-};
-
-#endif // STATISTICS_H_INCLUDED
diff --git a/library/status_handler.cpp b/library/status_handler.cpp
deleted file mode 100644
index 55f82c64..00000000
--- a/library/status_handler.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#include "status_handler.h"
-#include <wx/app.h>
-#include <ctime>
-
-void updateUiNow()
-{
- //process UI events and prevent application from "not responding" -> NO performance issue!
- wxTheApp->Yield();
-
- // while (wxTheApp->Pending())
- // wxTheApp->Dispatch();
-}
-
-
-bool updateUiIsAllowed()
-{
- const std::clock_t CLOCK_UPDATE_INTERVAL = UI_UPDATE_INTERVAL * CLOCKS_PER_SEC / 1000;
-
- static std::clock_t lastExec = 0;
- const std::clock_t now = std::clock(); //this is quite fast: 2 * 10^-5
-
- if (now - lastExec >= CLOCK_UPDATE_INTERVAL) //perform ui updates not more often than necessary
- {
- lastExec = now;
- return true;
- }
- return false;
-}
diff --git a/library/status_handler.h b/library/status_handler.h
deleted file mode 100644
index 1282f9f1..00000000
--- a/library/status_handler.h
+++ /dev/null
@@ -1,102 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-
-#ifndef STATUSHANDLER_H_INCLUDED
-#define STATUSHANDLER_H_INCLUDED
-
-#include <wx/string.h>
-#include <string>
-#include "../shared/int64.h"
-
-const int UI_UPDATE_INTERVAL = 100; //unit: [ms]; perform ui updates not more often than necessary, 100 seems to be a good value with only a minimal performance loss
-
-bool updateUiIsAllowed(); //test if a specific amount of time is over
-void updateUiNow(); //do the updating
-
-
-//interfaces for status updates (can be implemented by GUI or Batch mode)
-
-
-//report status during comparison and synchronization
-struct ProcessCallback
-{
- virtual ~ProcessCallback() {}
-
- //identifiers of different phases
- enum Process
- {
- PROCESS_NONE = 10,
- PROCESS_SCANNING,
- PROCESS_COMPARING_CONTENT,
- PROCESS_SYNCHRONIZING
- };
-
- //these methods have to be implemented in the derived classes to handle error and status information
- virtual void initNewProcess(int objectsTotal, zen::Int64 dataTotal, Process processID) = 0; //informs about the total amount of data that will be processed from now on
-
- //note: this one must NOT throw in order to properly allow undoing setting of statistics!
- //it is in general paired with a call to requestUiRefresh() to compensate!
- virtual void updateProcessedData(int objectsProcessed, zen::Int64 dataProcessed) = 0; //throw()
-
- //opportunity to abort must be implemented in a frequently executed method like requestUiRefresh()
- virtual void requestUiRefresh() = 0; //throw ?
-
- //this method is triggered repeatedly by requestUiRefresh() and can be used to refresh the ui by dispatching pending events
- virtual void forceUiRefresh() = 0;
-
- //called periodically after data was processed: expected(!) to request GUI update
- virtual void reportStatus(const wxString& text) = 0; //status info only, should not be logged!
-
- //called periodically after data was processed: expected(!) to request GUI update
- virtual void reportInfo(const wxString& text) = 0;
-
- virtual void reportWarning(const wxString& warningMessage, bool& warningActive) = 0;
-
- //error handling:
- enum Response
- {
- IGNORE_ERROR = 10,
- RETRY
- };
- virtual Response reportError (const wxString& errorMessage) = 0; //recoverable error situation
- virtual void reportFatalError(const wxString& errorMessage) = 0; //non-recoverable error situation
-};
-
-
-//gui may want to abort process
-struct AbortCallback
-{
- virtual ~AbortCallback() {}
- virtual void requestAbortion() = 0;
-};
-
-
-//actual callback implementation will have to satisfy "process" and "gui"
-class StatusHandler : public ProcessCallback, public AbortCallback
-{
-public:
- StatusHandler() : abortRequested(false) {}
-
- virtual void requestUiRefresh()
- {
- if (updateUiIsAllowed()) //test if specific time span between ui updates is over
- forceUiRefresh();
-
- if (abortRequested)
- abortThisProcess(); //abort can be triggered by requestAbortion()
- }
-
- virtual void abortThisProcess() = 0;
- virtual void requestAbortion() { abortRequested = true; } //this does NOT call abortThisProcess immediately, but when appropriate (e.g. async. processes finished)
- bool abortIsRequested() { return abortRequested; }
-
-private:
- bool abortRequested;
-};
-
-
-
-#endif // STATUSHANDLER_H_INCLUDED
bgstack15