summaryrefslogtreecommitdiff
path: root/library
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:07:43 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:07:43 +0200
commit4226e548662339ea1ca37b45385a7cf9b237ff1e (patch)
tree9a3fa54b85d97f05164e41bdb96b82f748a37342 /library
parent3.7 (diff)
downloadFreeFileSync-4226e548662339ea1ca37b45385a7cf9b237ff1e.tar.gz
FreeFileSync-4226e548662339ea1ca37b45385a7cf9b237ff1e.tar.bz2
FreeFileSync-4226e548662339ea1ca37b45385a7cf9b237ff1e.zip
3.8
Diffstat (limited to 'library')
-rw-r--r--library/CustomGrid.cpp314
-rw-r--r--library/CustomGrid.h10
-rw-r--r--library/FreeFileSync.icobin94198 -> 82726 bytes
-rw-r--r--library/dbFile.cpp59
-rw-r--r--library/dbFile.h6
-rw-r--r--library/filter.cpp3
-rw-r--r--library/iconBuffer.cpp346
-rw-r--r--library/iconBuffer.h25
-rw-r--r--library/multithreading.cpp254
-rw-r--r--library/multithreading.h41
-rw-r--r--library/pch.h4
-rw-r--r--library/processXml.cpp54
-rw-r--r--library/statistics.cpp14
13 files changed, 543 insertions, 587 deletions
diff --git a/library/CustomGrid.cpp b/library/CustomGrid.cpp
index 5fc993ce..a9846f74 100644
--- a/library/CustomGrid.cpp
+++ b/library/CustomGrid.cpp
@@ -16,11 +16,11 @@
#include "../synchronization.h"
#include "../shared/customTooltip.h"
#include <wx/dcclient.h>
+#include "iconBuffer.h"
+#include <wx/icon.h>
#ifdef FFS_WIN
#include <wx/timer.h>
-#include <wx/icon.h>
-#include "iconBuffer.h"
#include "statusHandler.h"
#include <cmath>
@@ -53,14 +53,6 @@ class CustomGridTable : public wxGridTableBase
public:
CustomGridTable(int initialRows = 0, int initialCols = 0) : //note: initialRows/initialCols MUST match with GetNumberRows()/GetNumberCols() at initialization!!!
wxGridTableBase(),
- COLOR_BLUE( 80, 110, 255),
- COLOR_GREY( 212, 208, 200),
- COLOR_CMP_RED( 249, 163, 165),
- COLOR_CMP_BLUE( 144, 232, 246),
- COLOR_CMP_GREEN( 147, 253, 159),
- COLOR_SYNC_BLUE( 201, 203, 247),
- COLOR_SYNC_GREEN(197, 248, 190),
- COLOR_YELLOW( 247, 252, 62),
gridDataView(NULL),
lastNrRows(initialRows),
lastNrCols(initialCols) {}
@@ -162,7 +154,7 @@ public:
virtual wxGridCellAttr* GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind)
{
- const wxColour& color = getRowColor(row);
+ const wxColour color = getRowColor(row);
//add color to some rows
wxGridCellAttr* result = wxGridTableBase::GetAttr(row, col, kind);
@@ -197,24 +189,36 @@ public:
}
protected:
- const wxColour COLOR_BLUE;
- const wxColour COLOR_GREY;
- const wxColour COLOR_CMP_RED;
- const wxColour COLOR_CMP_BLUE;
- const wxColour COLOR_CMP_GREEN;
- const wxColour COLOR_SYNC_BLUE;
- const wxColour COLOR_SYNC_GREEN;
- const wxColour COLOR_YELLOW;
+ 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_GREEN;
+ static const wxColour COLOR_YELLOW;
const GridView* gridDataView; //(very fast) access to underlying grid data :)
private:
- virtual const wxColour& getRowColor(int row) = 0; //rows that are filtered out are shown in different color
+ virtual const wxColour getRowColor(int row) = 0; //rows that are filtered out are shown in different color
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_GREEN(197, 248, 190);
+const wxColour CustomGridTable::COLOR_YELLOW( 247, 252, 62);
+
class CustomGridTableRim : public CustomGridTable
{
@@ -259,60 +263,143 @@ protected:
{
if (!fsObj->isEmpty<side>())
{
- const DirMapping* dirObj = dynamic_cast<const DirMapping*> (fsObj);
- if (dirObj != NULL)
+ struct GetValue : public FSObjectVisitor
{
- switch (getTypeAtPos(col))
+ GetValue(xmlAccess::ColumnTypes colType) : colType_(colType) {}
+ virtual void visit(const FileMapping& fileObj)
{
- case xmlAccess::FULL_PATH:
- return zToWx(dirObj->getFullName<side>());
- case xmlAccess::FILENAME:
- return wxEmptyString;
- case xmlAccess::REL_PATH:
- return zToWx(dirObj->getRelativeName<side>());
- case xmlAccess::DIRECTORY:
- return zToWx(dirObj->getBaseDirPf<side>());
- case xmlAccess::SIZE: //file size
- return _("<Directory>");
- case xmlAccess::DATE: //date
- return wxEmptyString;
- case xmlAccess::EXTENSION: //file extension
- return wxEmptyString;
+ switch (colType_)
+ {
+ case xmlAccess::FULL_PATH:
+ value = zToWx(fileObj.getFullName<side>().BeforeLast(globalFunctions::FILE_NAME_SEPARATOR));
+ break;
+ case xmlAccess::FILENAME: //filename
+ value = zToWx(fileObj.getShortName<side>());
+ break;
+ case xmlAccess::REL_PATH: //relative path
+ value = zToWx(fileObj.getParentRelativeName());
+ break;
+ case xmlAccess::DIRECTORY:
+ value = zToWx(fileObj.getBaseDirPf<side>());
+ break;
+ case xmlAccess::SIZE: //file size
+ value = FreeFileSync::numberToStringSep(fileObj.getFileSize<side>());
+ break;
+ case xmlAccess::DATE: //date
+ value = FreeFileSync::utcTimeToLocalString(fileObj.getLastWriteTime<side>());
+ break;
+ case xmlAccess::EXTENSION: //file extension
+ value = zToWx(fileObj.getExtension<side>());
+ break;
+ }
}
- }
- else
- {
- const FileMapping* fileObj = dynamic_cast<const FileMapping*>(fsObj);
- if (fileObj != NULL)
+
+ virtual void visit(const SymLinkMapping& linkObj)
{
- switch (getTypeAtPos(col))
+ switch (colType_)
{
case xmlAccess::FULL_PATH:
- return zToWx(fileObj->getFullName<side>().BeforeLast(globalFunctions::FILE_NAME_SEPARATOR));
+ value = zToWx(linkObj.getFullName<side>().BeforeLast(globalFunctions::FILE_NAME_SEPARATOR));
+ break;
case xmlAccess::FILENAME: //filename
- return zToWx(fileObj->getShortName<side>());
+ value = zToWx(linkObj.getShortName<side>());
+ break;
case xmlAccess::REL_PATH: //relative path
- return zToWx(fileObj->getParentRelativeName());
+ value = zToWx(linkObj.getParentRelativeName());
+ break;
case xmlAccess::DIRECTORY:
- return zToWx(fileObj->getBaseDirPf<side>());
+ value = zToWx(linkObj.getBaseDirPf<side>());
+ break;
case xmlAccess::SIZE: //file size
- return FreeFileSync::numberToWxString(fileObj->getFileSize<side>(), true);
+ value = _("<Symlink>");
+ break;
case xmlAccess::DATE: //date
- return FreeFileSync::utcTimeToLocalString(fileObj->getLastWriteTime<side>());
+ value = FreeFileSync::utcTimeToLocalString(linkObj.getLastWriteTime<side>());
+ break;
case xmlAccess::EXTENSION: //file extension
- return zToWx(fileObj->getExtension<side>());
+ value = wxEmptyString;
+ break;
}
}
- }
+
+ virtual void visit(const DirMapping& dirObj)
+ {
+ switch (colType_)
+ {
+ case xmlAccess::FULL_PATH:
+ value = zToWx(dirObj.getFullName<side>());
+ break;
+ case xmlAccess::FILENAME:
+ value = wxEmptyString;
+ break;
+ case xmlAccess::REL_PATH:
+ value = zToWx(dirObj.getRelativeName<side>());
+ break;
+ case xmlAccess::DIRECTORY:
+ value = zToWx(dirObj.getBaseDirPf<side>());
+ break;
+ case xmlAccess::SIZE: //file size
+ value = _("<Directory>");
+ break;
+ case xmlAccess::DATE: //date
+ value = wxEmptyString;
+ break;
+ case xmlAccess::EXTENSION: //file extension
+ value = wxEmptyString;
+ break;
+ }
+ }
+ xmlAccess::ColumnTypes colType_;
+ wxString value;
+ } getVal(getTypeAtPos(col));
+ 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:
+ //Icon should be the same on both sides anyway...
+ if (!fileObj.isEmpty<LEFT_SIDE>() && !fileObj.isEmpty<RIGHT_SIDE>())
+ iconName = fileObj.getFullName<LEFT_SIDE>();
+ else
+ iconName = fileObj.getFullName<side>();
+ }
+ virtual void visit(const SymLinkMapping& linkObj)
+ {
+ iconName = linkObj.getLinkType<side>() == LinkDescriptor::TYPE_DIR ?
+ DefaultStr("folder") :
+ linkObj.getFullName<side>();
+ }
+ virtual void visit(const DirMapping& dirObj)
+ {
+ iconName = DefaultStr("folder");
+ }
+
+ Zstring iconName;
+ } getIcon;
+ fsObj->accept(getIcon);
+ return getIcon.iconName;
+ }
+
+ return Zstring();
+ }
+
private:
- virtual const wxColour& getRowColor(int row) //rows that are filtered out are shown in different color
+ virtual const wxColour getRowColor(int row) //rows that are filtered out are shown in different color
{
const FileSystemObject* fsObj = getRawData(row);
if (fsObj)
@@ -320,11 +407,27 @@ private:
//mark filtered rows
if (!fsObj->isActive())
return COLOR_BLUE;
- //mark directories
- else if (isDirectoryMapping(*fsObj))
- return COLOR_GREY;
- else
- return *wxWHITE;
+
+ //mark directories and symlinks
+ struct GetRowColor : public FSObjectVisitor
+ {
+ virtual void visit(const FileMapping& fileObj)
+ {
+ rowColor = *wxWHITE;
+ }
+ virtual void visit(const SymLinkMapping& linkObj)
+ {
+ rowColor = COLOR_ORANGE;
+ }
+ virtual void visit(const DirMapping& dirObj)
+ {
+ rowColor = COLOR_GREY;
+ }
+
+ wxColour rowColor;
+ } getCol;
+ fsObj->accept(getCol);
+ return getCol.rowColor;
}
return *wxWHITE;
}
@@ -344,16 +447,7 @@ public:
virtual Zstring getIconFile(size_t row) const //return "folder" if row points to a folder
{
- const FileSystemObject* fsObj = getRawData(row);
- if (fsObj && !fsObj->isEmpty<LEFT_SIDE>())
- {
- if (isDirectoryMapping(*fsObj)) //it's a directory icon
- return DefaultStr("folder");
- else
- return fsObj->getFullName<LEFT_SIDE>();
- }
-
- return Zstring();
+ return getIconFileImpl<LEFT_SIDE>(row);
}
};
@@ -368,23 +462,7 @@ public:
virtual Zstring getIconFile(size_t row) const //return "folder" if row points to a folder
{
- const FileSystemObject* fsObj = getRawData(row);
- if (fsObj && !fsObj->isEmpty<RIGHT_SIDE>())
- {
- if (isDirectoryMapping(*fsObj)) //it's a directory icon
- return DefaultStr("folder");
- else
- {
- //Optimization: if filename exists on both sides, always use left side's file:
- //Icon should be the same on both sides anyway...
- if (!fsObj->isEmpty<LEFT_SIDE>())
- return fsObj->getFullName<LEFT_SIDE>();
- else
- return fsObj->getFullName<RIGHT_SIDE>();
- }
- }
-
- return Zstring();
+ return getIconFileImpl<RIGHT_SIDE>(row);
}
};
@@ -431,7 +509,7 @@ public:
}
private:
- virtual const wxColour& getRowColor(int row) //rows that are filtered out are shown in different color
+ virtual const wxColour getRowColor(int row) //rows that are filtered out are shown in different color
{
const FileSystemObject* fsObj = getRawData(row);
if (fsObj)
@@ -502,10 +580,6 @@ CustomGrid::CustomGrid(wxWindow *parent,
isLeading(false),
m_marker(-1, ASCENDING)
{
- SetLayoutDirection(wxLayout_LeftToRight); //
- GetGridWindow()->SetLayoutDirection(wxLayout_LeftToRight); //avoid mirroring this dialog in RTL languages like Hebrew or Arabic
- GetGridColLabelWindow()->SetLayoutDirection(wxLayout_LeftToRight); //
-
//set color of selections
wxColour darkBlue(40, 35, 140);
SetSelectionBackground(darkBlue);
@@ -550,6 +624,12 @@ void CustomGrid::initSettings(CustomGridLeft* gridLeft,
}
+void CustomGrid::release() //release connection to FreeFileSync::GridView
+{
+ setGridDataTable(NULL);
+}
+
+
bool CustomGrid::isLeadGrid() const
{
return isLeading;
@@ -574,7 +654,6 @@ void CustomGrid::OnPaintGrid(wxEvent& event)
}
-inline
void moveCursorWhileSelecting(const int anchor, const int oldPos, const int newPos, wxGrid* grid)
{
//note: all positions are valid in this context!
@@ -951,7 +1030,6 @@ std::set<size_t> CustomGrid::getAllSelectedRows() const
//############################################################################################
//CustomGrid specializations
-#ifdef FFS_WIN
template <bool showFileIcons>
class GridCellRenderer : public wxGridCellStringRenderer
{
@@ -1039,8 +1117,8 @@ public:
m_loadIconSuccess[row] = iconLoaded && iconDrawnFully;
}
}
+ return;
}
- return;
}
//default
@@ -1072,7 +1150,6 @@ private:
static const int LEFT_BORDER = 2;
};
-#endif
//----------------------------------------------------------------------------------------
@@ -1082,10 +1159,7 @@ CustomGridRim::CustomGridRim(wxWindow *parent,
const wxSize& size,
long style,
const wxString& name) :
- CustomGrid(parent, id, pos, size, style, name)
-#ifdef FFS_WIN
- , fileIconsAreEnabled(false)
-#endif
+ CustomGrid(parent, id, pos, size, style, name), fileIconsAreEnabled(false)
{}
@@ -1164,14 +1238,15 @@ xmlAccess::ColumnAttributes CustomGridRim::getColumnAttributes()
void CustomGridRim::setColumnAttributes(const xmlAccess::ColumnAttributes& attr)
{
//remove special alignment for column "size"
- 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;
- }
+ 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();
@@ -1222,14 +1297,15 @@ void CustomGridRim::setColumnAttributes(const xmlAccess::ColumnAttributes& attr)
//--------------------------------------------------------------------------------------------------------
//set special alignment for column "size"
- 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;
- }
+ 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();
@@ -1328,7 +1404,6 @@ void CustomGridRim::autoSizeColumns() //performance optimized column resizer (a
}
-#ifdef FFS_WIN
void CustomGridRim::enableFileIcons(const bool value)
{
fileIconsAreEnabled = value;
@@ -1449,7 +1524,6 @@ void IconUpdater::loadIconsAsynchronously(wxEvent& event) //loads all (not yet)
//event.Skip();
}
-#endif
//----------------------------------------------------------------------------------------
@@ -1591,6 +1665,11 @@ CustomGridMiddle::CustomGridMiddle(wxWindow *parent,
gridDataTable(NULL),
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);
@@ -1848,6 +1927,11 @@ void CustomGridMiddle::enableSyncPreview(bool value)
{
assert(gridDataTable);
gridDataTable->enableSyncPreview(value);
+
+ if (value)
+ GetGridColLabelWindow()->SetToolTip(_("Synchronization Preview"));
+ else
+ GetGridColLabelWindow()->SetToolTip(_("Comparison Result"));
}
diff --git a/library/CustomGrid.h b/library/CustomGrid.h
index 5f1823c0..0cace1a9 100644
--- a/library/CustomGrid.h
+++ b/library/CustomGrid.h
@@ -60,11 +60,13 @@ public:
virtual ~CustomGrid() {}
- void initSettings(CustomGridLeft* gridLeft,
+ void initSettings(CustomGridLeft* gridLeft, //create connection with FreeFileSync::GridView
CustomGridMiddle* gridMiddle,
CustomGridRight* gridRight,
const FreeFileSync::GridView* gridDataView);
+ void release(); //release connection to FreeFileSync::GridView
+
std::set<size_t> getAllSelectedRows() const;
//set sort direction indicator on UI
@@ -112,7 +114,6 @@ class GridCellRenderer;
//-----------------------------------------------------------
-#ifdef FFS_WIN
class IconUpdater : private wxEvtHandler //update file icons periodically: use SINGLE instance to coordinate left and right grid at once
{
public:
@@ -127,7 +128,6 @@ private:
std::auto_ptr<wxTimer> m_timer; //user timer event to periodically update icons: better than idle event because also active when scrolling! :)
};
-#endif
//############## SPECIALIZATIONS ###################
@@ -159,15 +159,12 @@ public:
void autoSizeColumns(); //performance optimized column resizer
void autoSizeColumns(int col, bool doRefresh = true); //
-#ifdef FFS_WIN
void enableFileIcons(const bool value);
-#endif
private:
CustomGridTableRim* getGridDataTable();
virtual const CustomGridTableRim* getGridDataTable() const = 0;
-#ifdef FFS_WIN
//asynchronous icon loading
void getIconsToBeLoaded(std::vector<Zstring>& newLoad); //loads all (not yet) drawn icons
@@ -183,7 +180,6 @@ private:
LoadSuccess loadIconSuccess; //save status of last icon load when drawing on GUI
bool fileIconsAreEnabled;
-#endif
xmlAccess::ColumnAttributes columnSettings; //set visibility, position and width of columns
};
diff --git a/library/FreeFileSync.ico b/library/FreeFileSync.ico
index bceb6ee4..bfa8ffc4 100644
--- a/library/FreeFileSync.ico
+++ b/library/FreeFileSync.ico
Binary files differ
diff --git a/library/dbFile.cpp b/library/dbFile.cpp
index 7a000197..1919dd6d 100644
--- a/library/dbFile.cpp
+++ b/library/dbFile.cpp
@@ -29,7 +29,7 @@ namespace
{
//-------------------------------------------------------------------------------------------------------------------------------
const char FILE_FORMAT_DESCR[] = "FreeFileSync";
-const int FILE_FORMAT_VER = 3;
+const int FILE_FORMAT_VER = 4;
//-------------------------------------------------------------------------------------------------------------------------------
@@ -86,18 +86,22 @@ public:
}
private:
- void execute(DirContainer& dirCont)
+ void execute(DirContainer& dirCont) const
{
- unsigned int fileCount = readNumberC<unsigned int>();
+ size_t fileCount = readNumberC<size_t>();
while (fileCount-- != 0)
readSubFile(dirCont);
- unsigned int dirCount = readNumberC<unsigned int>();
+ size_t symlinkCount = readNumberC<size_t>();
+ while (symlinkCount-- != 0)
+ readSubLink(dirCont);
+
+ size_t dirCount = readNumberC<size_t>();
while (dirCount-- != 0)
readSubDirectory(dirCont);
}
- void readSubFile(DirContainer& 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(); //file name
@@ -116,7 +120,22 @@ private:
wxULongLong(sizeHigh, sizeLow)));
}
- void readSubDirectory(DirContainer& dirCont)
+
+ void readSubLink(DirContainer& dirCont) const
+ {
+ //attention: order of function argument evaluation is undefined! So do it one after the other...
+ const Zstring shortName = readStringC(); //file name
+ const long modHigh = readNumberC<long>();
+ const unsigned long modLow = readNumberC<unsigned long>();
+ const Zstring targetPath = readStringC(); //file name
+ const LinkDescriptor::LinkType linkType = static_cast<LinkDescriptor::LinkType>(readNumberC<int>());
+
+ dirCont.addSubLink(shortName,
+ LinkDescriptor(wxLongLong(modHigh, modLow), targetPath, linkType));
+ }
+
+
+ void readSubDirectory(DirContainer& dirCont) const
{
const Zstring shortName = readStringC(); //directory name
DirContainer& subDir = dirCont.addSubDir(shortName);
@@ -254,16 +273,20 @@ public:
}
private:
- template<typename Iterator, typename Function>
- friend Function std::for_each(Iterator, Iterator, Function);
+ friend class Utility::Proxy<SaveDirInfo<side> >; //friend declaration of std::for_each is NOT sufficient as implementation is compiler dependent!
void execute(const HierarchyObject& hierObj)
{
- writeNumberC<unsigned int>(std::count_if(hierObj.useSubFiles().begin(), hierObj.useSubFiles().end(), IsNonEmpty<side>())); //number of (existing) files
- std::for_each(hierObj.useSubFiles().begin(), hierObj.useSubFiles().end(), *this);
+ Utility::Proxy<SaveDirInfo<side> > prx(*this); //grant std::for_each access to private parts of this class
- writeNumberC<unsigned int>(std::count_if(hierObj.useSubDirs().begin(), hierObj.useSubDirs().end(), IsNonEmpty<side>())); //number of (existing) directories
- std::for_each(hierObj.useSubDirs().begin(), hierObj.useSubDirs().end(), *this);
+ writeNumberC<size_t>(std::count_if(hierObj.useSubFiles().begin(), hierObj.useSubFiles().end(), IsNonEmpty<side>())); //number of (existing) files
+ std::for_each(hierObj.useSubFiles().begin(), hierObj.useSubFiles().end(), prx);
+
+ writeNumberC<size_t>(std::count_if(hierObj.useSubLinks().begin(), hierObj.useSubLinks().end(), IsNonEmpty<side>())); //number of (existing) files
+ std::for_each(hierObj.useSubLinks().begin(), hierObj.useSubLinks().end(), prx);
+
+ writeNumberC<size_t>(std::count_if(hierObj.useSubDirs().begin(), hierObj.useSubDirs().end(), IsNonEmpty<side>())); //number of (existing) directories
+ std::for_each(hierObj.useSubDirs().begin(), hierObj.useSubDirs().end(), prx);
}
void operator()(const FileMapping& fileMap)
@@ -281,6 +304,18 @@ private:
}
}
+ void operator()(const SymLinkMapping& linkObj)
+ {
+ if (!linkObj.isEmpty<side>())
+ {
+ writeStringC(linkObj.getObjShortName());
+ writeNumberC<long>( linkObj.getLastWriteTime<side>().GetHi()); //last modification time
+ writeNumberC<unsigned long>(linkObj.getLastWriteTime<side>().GetLo()); //
+ writeStringC(linkObj.getTargetPath<side>());
+ writeNumberC<int>(linkObj.getLinkType<side>());
+ }
+ }
+
void operator()(const DirMapping& dirMap)
{
if (!dirMap.isEmpty<side>())
diff --git a/library/dbFile.h b/library/dbFile.h
index e7db0393..9fa49c51 100644
--- a/library/dbFile.h
+++ b/library/dbFile.h
@@ -13,7 +13,13 @@ namespace FreeFileSync
{
void saveToDisk(const BaseDirMapping& baseMapping); //throw (FileError)
+struct DirInformation
+{
+ BaseFilter::FilterRef filter; //filter settings (used when retrieving directory data)
+ DirContainer baseDirContainer; //hierarchical directory information
+};
typedef boost::shared_ptr<const DirInformation> DirInfoPtr;
+
std::pair<DirInfoPtr, DirInfoPtr> loadFromDisk(const BaseDirMapping& baseMapping); //throw (FileError) -> return value always bound!
}
diff --git a/library/filter.cpp b/library/filter.cpp
index 931532c3..a64c3a31 100644
--- a/library/filter.cpp
+++ b/library/filter.cpp
@@ -251,8 +251,7 @@ bool NameFilter::passDirFilter(const Zstring& relDirname, bool* subObjMightMatch
{
if (subObjMightMatch)
{
- Zstring subNameBegin = relDirname;
- subNameBegin += globalFunctions::FILE_NAME_SEPARATOR;
+ const Zstring& subNameBegin = relDirname + globalFunctions::FILE_NAME_SEPARATOR; //const-ref optimization
*subObjMightMatch = matchesFilterBegin(subNameBegin, filterFileIn) || //might match a file in subdirectory
matchesFilterBegin(subNameBegin, filterFolderIn); //or another subdirectory
diff --git a/library/iconBuffer.cpp b/library/iconBuffer.cpp
index 338f53df..fa0b1673 100644
--- a/library/iconBuffer.cpp
+++ b/library/iconBuffer.cpp
@@ -7,7 +7,6 @@
#include "iconBuffer.h"
#include <wx/thread.h>
#include <wx/bitmap.h>
-#include <wx/msw/wrapwin.h> //includes "windows.h"
#include <wx/msgdlg.h>
#include <wx/icon.h>
#include <map>
@@ -15,42 +14,34 @@
#include <stdexcept>
#include <set>
-using FreeFileSync::IconBuffer;
+#ifdef FFS_WIN
+#include <wx/msw/wrapwin.h> //includes "windows.h"
+#elif defined FFS_LINUX
+#include <giomm/file.h>
+#include <gtkmm/icontheme.h>
+#include <gtkmm/main.h>
+#endif
-const wxIcon& IconBuffer::getDirectoryIcon() //one folder icon should be sufficient...
-{
- static wxIcon folderIcon;
- static bool isInitalized = false;
- if (!isInitalized)
- {
- isInitalized = true;
-
- SHFILEINFO fileInfo;
- fileInfo.hIcon = 0; //initialize hIcon
-
- //NOTE: CoInitializeEx()/CoUninitialize() implicitly called by wxWidgets on program startup!
- if (::SHGetFileInfo(DefaultStr("dummy"), //Windows Seven doesn't like this parameter to be an empty string
- FILE_ATTRIBUTE_DIRECTORY,
- &fileInfo,
- sizeof(fileInfo),
- SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES) &&
+using FreeFileSync::IconBuffer;
- fileInfo.hIcon != 0) //fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!!
- {
- folderIcon.SetHICON(fileInfo.hIcon);
- folderIcon.SetSize(IconBuffer::ICON_SIZE, IconBuffer::ICON_SIZE);
- }
- }
- return folderIcon;
-}
namespace
{
+struct CmpFilename
+{
+ bool operator()(const Zstring& a, const Zstring& b) const
+ {
+ return a.cmpFileName(b) < 0;
+ }
+};
+
+
+#ifdef FFS_WIN
Zstring getFileExtension(const Zstring& filename)
{
- const Zstring shortName = filename.AfterLast(DefaultChar('\\')); //Zstring::AfterLast() returns the whole string if ch not found
+ const Zstring shortName = filename.AfterLast(DefaultChar('\\')); //warning: using windows file name separator!
const size_t pos = shortName.Find(DefaultChar('.'), true);
return pos == Zstring::npos ?
Zstring() :
@@ -58,19 +49,10 @@ Zstring getFileExtension(const Zstring& filename)
}
-struct CmpFilenameWin
-{
- bool operator()(const Zstring& a, const Zstring& b) const
- {
- return a.cmpFileName(b) < 0;
- }
-};
-
-
//test for extension for icons that physically have to be retrieved from disc
bool isPriceyExtension(const Zstring& extension)
{
- static std::set<Zstring, CmpFilenameWin> exceptions;
+ static std::set<Zstring, CmpFilename> exceptions;
static bool isInitalized = false;
if (!isInitalized)
{
@@ -86,39 +68,198 @@ bool isPriceyExtension(const Zstring& extension)
}
return exceptions.find(extension) != exceptions.end();
}
+#endif
}
//################################################################################################################################################
-class IconBuffer::IconHolder //handle HICON ownership WITHOUT ref-counting to allow a deep-copy (in contrast to wxIcon)
+class IconBuffer::IconHolder //handle HICON/GdkPixbuf ownership WITHOUT ref-counting to allow thread-safe usage (in contrast to wxIcon)
{
public:
- IconHolder(HICON handle = 0) : handle_(handle) {}
+#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_ == 0 ? 0 :
+#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_ != 0)
+#ifdef FFS_WIN
::DestroyIcon(handle_);
+#elif defined FFS_LINUX
+ g_object_unref(handle_);
+#endif
}
- HICON clone() const //copy HICON, caller needs to take ownership!
+ void swap(IconHolder& other) //throw()
{
- return handle_ != 0 ? ::CopyIcon(handle_) : 0;
+ std::swap(handle_, other.handle_);
}
- void swap(IconHolder& other) //throw()
+ wxIcon toWxIcon() const //copy HandleType, caller needs to take ownership!
{
- std::swap(handle_, other.handle_);
+ IconHolder clone(*this);
+ if (clone.handle_ != 0)
+ {
+ wxIcon newIcon; //attention: wxIcon uses reference counting!
+#ifdef FFS_WIN
+ newIcon.SetHICON(clone.handle_); //
+ newIcon.SetSize(IconBuffer::ICON_SIZE, IconBuffer::ICON_SIZE); //icon is actually scaled to this size (just in case referenced HICON differs)
+#elif defined FFS_LINUX //
+ newIcon.SetPixbuf(clone.handle_); // transfer ownership!!
+#endif //
+ clone.handle_ = 0; //
+ return newIcon;
+ }
+ return wxNullIcon;
}
private:
- IconHolder(const IconHolder&);
- IconHolder& operator=(const IconHolder&);
-
- HICON handle_;
+ HandleType handle_;
};
+const wxIcon& IconBuffer::getDirectoryIcon() //one folder icon should be sufficient...
+{
+ static wxIcon folderIcon;
+
+ static bool isInitalized = false;
+ if (!isInitalized)
+ {
+ isInitalized = true;
+
+#ifdef FFS_WIN
+ SHFILEINFO fileInfo;
+ fileInfo.hIcon = 0; //initialize hIcon
+
+ //NOTE: CoInitializeEx()/CoUninitialize() implicitly called by wxWidgets on program startup!
+ if (::SHGetFileInfo(DefaultStr("dummy"), //Windows Seven doesn't like this parameter to be an empty string
+ FILE_ATTRIBUTE_DIRECTORY,
+ &fileInfo,
+ sizeof(fileInfo),
+ SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES) &&
+
+ fileInfo.hIcon != 0) //fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!!
+ {
+ folderIcon.SetHICON(fileInfo.hIcon); //transfer ownership!
+ folderIcon.SetSize(IconBuffer::ICON_SIZE, IconBuffer::ICON_SIZE);
+ }
+
+#elif defined FFS_LINUX
+ folderIcon = getAssociatedIcon(DefaultStr("/usr/")).toWxIcon(); //all directories will look like "/usr/"
+#endif
+ }
+ return folderIcon;
+}
+
+
+IconBuffer::IconHolder IconBuffer::getAssociatedIcon(const Zstring& filename)
+{
+#ifdef FFS_WIN
+ //despite what docu says about SHGetFileInfo() it can't handle all relative filenames, e.g. "\DirName"
+ //but no problem, directory formatting takes care that filenames are always absolute!
+
+ SHFILEINFO fileInfo;
+ fileInfo.hIcon = 0; //initialize hIcon -> fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!!
+ //bug report: https://sourceforge.net/tracker/?func=detail&aid=2768004&group_id=234430&atid=1093080
+
+ //NOTE: CoInitializeEx()/CoUninitialize() implicitly called by wxWidgets on program startup!
+ ::SHGetFileInfo(filename.c_str(), //FreeFileSync::removeLongPathPrefix(fileName), //::SHGetFileInfo() can't handle \\?\-prefix!
+ 0,
+ &fileInfo,
+ sizeof(fileInfo),
+ SHGFI_ICON | SHGFI_SMALLICON);
+
+ return IconHolder(fileInfo.hIcon); //pass icon ownership (may be 0)
+
+#elif defined FFS_LINUX
+ static struct RunOnce
+ {
+ RunOnce()
+ {
+ Gtk::Main::init_gtkmm_internals();
+ }
+ } dummy;
+
+ 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, ICON_SIZE, 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&) {}
+
+
+ //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", ICON_SIZE, Gtk::ICON_LOOKUP_USE_BUILTIN);
+ if (!iconPixbuf)
+ iconPixbuf = iconTheme->load_icon("text-x-generic", ICON_SIZE, Gtk::ICON_LOOKUP_USE_BUILTIN);
+ if (iconPixbuf)
+ return IconHolder(iconPixbuf->gobj_copy()); //copy and pass icon ownership (may be 0)
+ }
+
+ //fallback fallback
+ return IconHolder();
+#endif
+}
+
+
+#ifdef FFS_WIN
+IconBuffer::IconHolder IconBuffer::getAssociatedIconByExt(const Zstring& extension)
+{
+ SHFILEINFO fileInfo;
+ fileInfo.hIcon = 0; //initialize hIcon -> fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!!
+
+ //no read-access to disk! determine icon by extension
+ ::SHGetFileInfo((Zstring(DefaultStr("dummy.")) + extension).c_str(), //Windows Seven doesn't like this parameter to be without short name
+ FILE_ATTRIBUTE_NORMAL,
+ &fileInfo,
+ sizeof(fileInfo),
+ SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES);
+
+ return IconHolder(fileInfo.hIcon); //pass icon ownership (may be 0)
+}
+#endif
+
+
//---------------------------------------------------------------------------------------------------
typedef std::vector<DefaultChar> BasicString; //simple thread safe string class: std::vector is guaranteed to not use reference counting, Effective STL, item 13
//avoid reference-counted objects as shared data: NOT THREADSAFE!!! (implicitly shared variables: ref-count + c-string)
@@ -144,10 +285,9 @@ private:
wxCriticalSection lockWorkload; //use for locking shared data
std::vector<FileName> workload; //processes last elements of vector first!
bool threadHasMutex;
- bool threadExitIsRequested;
//------------------------------------------------------------
- //event: icon buffer -> woker thread
+ //signal event: icon buffer(main thread) -> worker thread
wxMutex threadIsListening;
wxCondition continueWork; //wake up thread
@@ -156,9 +296,8 @@ private:
IconBuffer::WorkerThread::WorkerThread(IconBuffer* iconBuff) :
- wxThread(wxTHREAD_JOINABLE),
+ wxThread(wxTHREAD_DETACHED), //we're using the thread encapsulated in a static object => use "detached" to avoid main thread waiting for this thread on exit(which in turn would prevent deletion of static object...ect.) => deadlock!
threadHasMutex(false),
- threadExitIsRequested(false),
threadIsListening(),
continueWork(threadIsListening),
iconBuffer(iconBuff)
@@ -195,12 +334,8 @@ void IconBuffer::WorkerThread::setWorkload(const std::vector<Zstring>& load) //(
void IconBuffer::WorkerThread::quitThread()
{
- {
- wxMutexLocker dummy(threadIsListening); //wait until thread is in waiting state
- threadExitIsRequested = true; //no sharing conflicts in this situation
- continueWork.Signal(); //exit thread
- }
- Wait(); //wait until thread has exitted
+ setWorkload(std::vector<Zstring>());
+ Delete(); //gracefully terminate a detached thread...
}
@@ -208,22 +343,20 @@ wxThread::ExitCode IconBuffer::WorkerThread::Entry()
{
try
{
- wxMutexLocker dummy(threadIsListening); //this lock needs to be called from WITHIN the thread => calling it from constructor(Main thread) would be useless
+ //this lock needs to be called from WITHIN the thread => calling it from constructor(Main thread) would be useless (signal direction: main -> thread)
+ wxMutexLocker dummy(threadIsListening); //this mutex STAYS locked all the time except of continueWork.Wait()!
{
- //this mutex STAYS locked all the time except of continueWork.Wait()!
wxCriticalSectionLocker dummy2(lockWorkload);
threadHasMutex = true;
}
while (true)
{
- continueWork.Wait(); //waiting for continueWork.Signal(); unlocks Mutex "threadIsListening"
+ continueWork.WaitTimeout(100); //waiting for continueWork.Signal(); unlocks Mutex "threadIsListening"
- //no mutex needed in this context
- if (threadExitIsRequested) //no mutex here: atomicity is not prob for a bool, but visibility (e.g. caching in registers)
- return 0; //shouldn't be a problem nevertheless because of implicit memory barrier caused by mutex.Lock() in .Wait()
+ if (TestDestroy())
+ return 0;
- //do work: get the file icons
doWork();
}
}
@@ -237,60 +370,43 @@ wxThread::ExitCode IconBuffer::WorkerThread::Entry()
void IconBuffer::WorkerThread::doWork()
{
- Zstring fileName;
-
//do work: get the file icon.
while (true)
{
+ Zstring fileName;
{
wxCriticalSectionLocker dummy(lockWorkload);
if (workload.empty())
break; //enter waiting state
- fileName = &workload.back()[0]; //deep copy: fileName is NOT empty (includes NULL-termination)
+ fileName = &workload.back()[0]; //deep copy (includes NULL-termination)
workload.pop_back();
}
if (iconBuffer->requestFileIcon(fileName)) //thread safety: Zstring okay, won't be reference-counted in requestIcon()
continue; //icon already in buffer: skip
- //despite what docu says about SHGetFileInfo() it can't handle all relative filenames, e.g. "\DirName"
- //but no problem, directory formatting takes care that filenames are always absolute!
-
- //load icon
- SHFILEINFO fileInfo;
- fileInfo.hIcon = 0; //initialize hIcon -> fix for weird error: SHGetFileInfo() might return successfully WITHOUT filling fileInfo.hIcon!!
- //bug report: https://sourceforge.net/tracker/?func=detail&aid=2768004&group_id=234430&atid=1093080
-
+#ifdef FFS_WIN
const Zstring extension = getFileExtension(fileName); //thread-safe: no sharing!
if (isPriceyExtension(extension)) //"pricey" extensions are stored with fullnames and are read from disk, while cheap ones require just the extension
{
- //NOTE: CoInitializeEx()/CoUninitialize() implicitly called by wxWidgets on program startup!
- ::SHGetFileInfo(fileName.c_str(), //FreeFileSync::removeLongPathPrefix(fileName), //::SHGetFileInfo() can't handle \\?\-prefix!
- 0,
- &fileInfo,
- sizeof(fileInfo),
- SHGFI_ICON | SHGFI_SMALLICON);
-
- IconBuffer::IconHolder newIcon(fileInfo.hIcon); //pass icon ownership (may be 0)
+ const IconHolder newIcon = IconBuffer::getAssociatedIcon(fileName);
iconBuffer->insertIntoBuffer(fileName, newIcon);
}
else //no read-access to disk! determine icon by extension
{
- ::SHGetFileInfo((Zstring(DefaultStr("dummy.")) + extension).c_str(), //Windows Seven doesn't like this parameter to be without short name
- FILE_ATTRIBUTE_NORMAL,
- &fileInfo,
- sizeof(fileInfo),
- SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES);
-
- IconBuffer::IconHolder newIcon(fileInfo.hIcon); //pass icon ownership (may be 0)
+ const IconHolder newIcon = IconBuffer::getAssociatedIconByExt(extension);
iconBuffer->insertIntoBuffer(extension, newIcon);
}
+#elif defined FFS_LINUX
+ const IconHolder newIcon = IconBuffer::getAssociatedIcon(fileName);
+ iconBuffer->insertIntoBuffer(fileName, newIcon);
+#endif
}
}
//---------------------------------------------------------------------------------------------------
-class IconBuffer::IconDB : public std::map<Zstring, IconBuffer::CountedIconPtr> {}; //entryName/icon -> ATTENTION: consider ref-counting for this shared data structure!!!
+class IconBuffer::IconDB : public std::map<Zstring, IconBuffer::IconHolder> {}; //entryName/icon -> ATTENTION: avoid ref-counting for this shared data structure!!! (== don't copy instances between threads)
class IconBuffer::IconDbSequence : public std::queue<Zstring> {}; //entryName
//---------------------------------------------------------------------------------------------------
@@ -312,42 +428,29 @@ IconBuffer::IconBuffer() :
IconBuffer::~IconBuffer()
{
- //keep non-inline destructor for std::auto_ptr to work with forward declarations
-
worker->quitThread();
}
bool IconBuffer::requestFileIcon(const Zstring& fileName, wxIcon* icon)
{
+ wxCriticalSectionLocker dummy(*lockIconDB);
+
+#ifdef FFS_WIN
+ //"pricey" extensions are stored with fullnames and are read from disk, while cheap ones require just the extension
const Zstring extension = getFileExtension(fileName);
+ IconDB::const_iterator i = buffer->find(isPriceyExtension(extension) ? fileName : extension);
+#elif defined FFS_LINUX
+ IconDB::const_iterator i = buffer->find(fileName);
+#endif
- wxCriticalSectionLocker dummy(*lockIconDB);
+ if (i == buffer->end())
+ return false;
- IconDB::const_iterator i = buffer->find( //"pricey" extensions are stored with fullnames and are read from disk, while cheap ones require just the extension
- isPriceyExtension(extension) ?
- fileName :
- extension);
- if (i != buffer->end())
- {
- if (icon != NULL)
- {
- HICON clonedIcon = i->second->clone(); //thread safety: make deep copy!
- if (clonedIcon != 0)
- {
- //create wxIcon from handle
- wxIcon newIcon; //attention: wxIcon uses reference counting!
- newIcon.SetHICON(clonedIcon); //transfer ownership!!
- newIcon.SetSize(IconBuffer::ICON_SIZE, IconBuffer::ICON_SIZE);
- *icon = newIcon;
- }
- else
- *icon = wxNullIcon;
- }
- return true;
- }
+ if (icon != NULL)
+ *icon = i->second.toWxIcon();
- return false;
+ return true;
}
@@ -357,16 +460,14 @@ void IconBuffer::setWorkload(const std::vector<Zstring>& load)
}
-void IconBuffer::insertIntoBuffer(const DefaultChar* entryName, IconHolder& icon) //called by worker thread
+void IconBuffer::insertIntoBuffer(const DefaultChar* entryName, const IconHolder& icon) //called by worker thread
{
wxCriticalSectionLocker dummy(*lockIconDB);
//thread safety, ref-counting: (implicitly) make deep copy!
const Zstring fileNameZ = entryName;
- const IconBuffer::CountedIconPtr newIcon(new IconBuffer::IconHolder); //exception safety!
- newIcon->swap(icon); //
- const std::pair<IconDB::iterator, bool> rc = buffer->insert(IconDB::value_type(fileNameZ, newIcon)); //thread saftey: icon uses ref-counting! But is NOT shared with main thread!
+ const std::pair<IconDB::iterator, bool> rc = buffer->insert(std::make_pair(fileNameZ, icon)); //thread saftey: icon uses ref-counting! But is NOT shared with main thread!
if (rc.second) //if insertion took place
bufSequence->push(fileNameZ); //note: sharing Zstring with IconDB!!!
@@ -381,4 +482,3 @@ void IconBuffer::insertIntoBuffer(const DefaultChar* entryName, IconHolder& icon
bufSequence->pop();
}
}
-
diff --git a/library/iconBuffer.h b/library/iconBuffer.h
index cb2d809f..4a19af3d 100644
--- a/library/iconBuffer.h
+++ b/library/iconBuffer.h
@@ -7,14 +7,9 @@
#ifndef ICONBUFFER_H_INCLUDED
#define ICONBUFFER_H_INCLUDED
-#ifndef FFS_WIN
-header should be used in the windows build only!
-#endif
-
#include <vector>
#include "../shared/zstring.h"
#include <memory>
-#include <boost/shared_ptr.hpp>
class wxCriticalSection;
class wxIcon;
@@ -32,24 +27,27 @@ public:
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 const int ICON_SIZE = 16; //size in pixel
- static const size_t BUFFER_SIZE = 800; //maximum number if icons to buffer
+#ifdef FFS_WIN
+ static const int ICON_SIZE = 16; //size in pixel
+#elif defined FFS_LINUX
+ static const int ICON_SIZE = 24; //size in pixel
+#endif
private:
IconBuffer();
~IconBuffer();
- class WorkerThread;
- friend class WorkerThread;
+ static const size_t BUFFER_SIZE = 800; //maximum number of icons to buffer
class IconDB;
class IconHolder;
class IconDbSequence;
- typedef boost::shared_ptr<IconHolder> CountedIconPtr;
-
//methods used by worker thread
- void insertIntoBuffer(const DefaultChar* entryName, IconHolder& icon); //icon is invalidated by this call!!
+ void insertIntoBuffer(const DefaultChar* entryName, const IconHolder& icon);
+
+ static IconHolder getAssociatedIcon(const Zstring& filename);
+ static IconHolder getAssociatedIconByExt(const Zstring& extension);
//---------------------- Shared Data -------------------------
std::auto_ptr<wxCriticalSection> lockIconDB;
@@ -57,7 +55,8 @@ private:
std::auto_ptr<IconDbSequence> bufSequence; //save sequence of buffer entry to delete oldest elements (implicitly shared by sharing Zstring with IconDB!!!)
//------------------------------------------------------------
- std::auto_ptr<WorkerThread> worker;
+ class WorkerThread;
+ WorkerThread* worker; //detached thread => destroys itself
};
}
diff --git a/library/multithreading.cpp b/library/multithreading.cpp
deleted file mode 100644
index 252884a2..00000000
--- a/library/multithreading.cpp
+++ /dev/null
@@ -1,254 +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-2010 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-//
-#include "multithreading.h"
-#include "statusHandler.h"
-#include <wx/utils.h>
-
-//#include <wx/msw/wrapwin.h> //includes "windows.h"
-//MessageBox(0, "hi", "", 0);
-
-/*choreography:
-
- ------------- ---------------
- |main thread| |worker thread|
- ------------- ---------------
-
-1. Instantiation (Constructor)
--------------------------------
- create thread
- enter waiting state
-2. waitUntilReady
--------------------------------
- wait until thread is ready
-
-3. Call execute
--------------------------------
- send signal to start
- start processing
- update UI while thread works
- finish processing
- wait until main thread is ready to receive signal
- receive signal
- enter waiting state
-4. Termination (Destructor)
--------------------------------
- wait until thread is in wait state
- set exit flag
- signal thread to continue (and exit)
-*/
-class WorkerThread : public wxThread
-{
- friend class UpdateWhileExecuting;
-
-public:
- WorkerThread(UpdateWhileExecuting* handler) :
- wxThread(wxTHREAD_DETACHED),
- readyToBeginProcessing(),
- beginProcessing(readyToBeginProcessing),
- threadIsInitialized(false),
- threadExitIsRequested(false),
- threadHandler(handler)
- { }
-
-
- ~WorkerThread() {}
-
-
- ExitCode Entry()
- {
- readyToBeginProcessing.Lock(); //this lock needs to be called IN the thread => calling it from constructor(Main thread) would be useless
- sharedData.Enter();
- threadIsInitialized = true;
- sharedData.Leave();
-
- while (true)
- {
- beginProcessing.Wait();
-
- //no mutex needed in this context
- if (threadExitIsRequested)
- return 0;
-
- //actual (long running) work is done in this method
- threadHandler->longRunner();
-
- threadHandler->readyToReceiveResult.Lock();
- threadHandler->receivingResult.Signal(); // kind of a double notice that work is completed
- threadHandler->workDone = true; // Workaround for wxWidgets: bug in wxCondition (wxWidgets v2.8.9, signal might geht lost)
- threadHandler->readyToReceiveResult.Unlock();
- }
-
- return 0;
- }
-
-private:
- wxMutex readyToBeginProcessing;
- wxCondition beginProcessing;
-
- //shared data
- wxCriticalSection sharedData;
- bool threadIsInitialized;
- bool threadExitIsRequested;
-
- UpdateWhileExecuting* threadHandler;
-};
-
-
-UpdateWhileExecuting::UpdateWhileExecuting() :
- readyToReceiveResult(),
- receivingResult(readyToReceiveResult),
- workDone(false)
-{
- //mutex needs to be initially locked for condition receivingResult to work properly
- readyToReceiveResult.Lock();
-
-
- theWorkerThread = new WorkerThread(this);
-
- theWorkerThread->Create();
- theWorkerThread->Run();
-
- //wait until the thread has locked readyToBeginProcessing
- bool threadInitialized = false;
- while (!threadInitialized)
- {
- theWorkerThread->sharedData.Enter();
- threadInitialized = theWorkerThread->threadIsInitialized;
- theWorkerThread->sharedData.Leave();
- wxMilliSleep(5);
- } //-> it's not nice, but works and is no issue
-}
-
-
-UpdateWhileExecuting::~UpdateWhileExecuting()
-{
- //wait until thread is ready, then start and exit immediately
- readyToReceiveResult.Unlock(); //avoid possible deadlock, when thread might be waiting to send the signal
-
- theWorkerThread->readyToBeginProcessing.Lock();
- //set flag to exit thread
- theWorkerThread->threadExitIsRequested = true;
- theWorkerThread->beginProcessing.Signal();
-
- theWorkerThread->readyToBeginProcessing.Unlock();
- //theWorkerThread deletes itself!
-}
-
-
-void UpdateWhileExecuting::waitUntilReady()
-{
- readyToReceiveResult.Unlock(); //avoid possible deadlock, when thread might be waiting to send the signal (if abort was pressed)
-
- theWorkerThread->readyToBeginProcessing.Lock();
-
- workDone = false; //no mutex needed here (worker thread that changes this variable is in waiting state)
-}
-// /|\ \|/ must be called directly after each other
-
-void UpdateWhileExecuting::execute(StatusHandler* statusUpdater)
-{
- readyToReceiveResult.Lock();
-
- theWorkerThread->beginProcessing.Signal();
- theWorkerThread->readyToBeginProcessing.Unlock();
-
- while (receivingResult.WaitTimeout(UI_UPDATE_INTERVAL) == wxCOND_TIMEOUT)
- {
- statusUpdater->requestUiRefresh(false); //don't allow throwing exception within this call
-
- if (workDone) //workaround for a bug in wxWidgets v2.8.9 class wxCondition: signals might get lost
- break; //no mutex for workDone needed here: it is changed only when mainthread is in WaitTimeout()
- }
-}
-
-
-
-// ------------------------------------------------------
-// |Pattern: workload queue and multiple worker threads |
-// ------------------------------------------------------
-//typedef std::vector<DirectoryDescrType*> Workload;
-//
-//class ThreadSorting : public wxThread
-//{
-//public:
-// ThreadSorting(wxCriticalSection& syncWorkload, Workload& workload) :
-// wxThread(wxTHREAD_JOINABLE),
-// syncWorkload_(syncWorkload),
-// workload_(workload)
-// {
-// if (Create() != wxTHREAD_NO_ERROR)
-// throw RuntimeException(wxString(wxT("Error creating thread for sorting!")));
-// }
-//
-// ~ThreadSorting() {}
-//
-//
-// ExitCode Entry()
-// {
-// while (true)
-// {
-// DirectoryDescrType* descr = NULL;
-// { //see if there is work to do...
-// wxCriticalSectionLocker dummy(syncWorkload_);
-// if (workload_.empty())
-// return 0;
-// else
-// {
-// descr = workload_.back();
-// workload_.pop_back();
-// }
-// }
-// //do work
-// std::sort(descr->begin(), descr->end());
-// }
-// }
-//
-//private:
-// wxCriticalSection& syncWorkload_;
-// Workload& workload_;
-//};
-//
-//
-//void DirectoryDescrBuffer::preFillBuffers(const std::vector<FolderPairCfg>& fpConfigFormatted)
-//{
-// //assemble workload
-// ...
-//
-// //we use binary search when comparing the directory structures: so sort() first
-// const int CPUCount = wxThread::GetCPUCount();
-// if (CPUCount >= 2) //do it the multithreaded way:
-// {
-// wxCriticalSection syncWorkload;
-//
-// typedef std::vector<boost::shared_ptr<ThreadSorting> > ThreadContainer;
-// ThreadContainer sortThreads;
-// sortThreads.reserve(CPUCount);
-//
-// //start CPUCount worker threads
-// for (size_t i = 0; i < std::min(static_cast<size_t>(CPUCount), workload.size()); ++i)
-// {
-// boost::shared_ptr<ThreadSorting> newWorker(new ThreadSorting(syncWorkload, workload));
-//
-// if (newWorker->Run() != wxTHREAD_NO_ERROR)
-// throw RuntimeException(wxString(wxT("Error starting thread for sorting!")));
-//
-// sortThreads.push_back(newWorker);
-// }
-//
-// //wait until all worker are finished
-// for (ThreadContainer::iterator i = sortThreads.begin(); i != sortThreads.end(); ++i)
-// {
-// if ((*i)->Wait() != 0)
-// throw RuntimeException(wxString(wxT("Error waiting for thread (sorting)!")));
-// }
-// }
-// else //single threaded
-// {
-// for (Workload::iterator i = workload.begin(); i != workload.end(); ++i)
-// std::sort((*i)->begin(), (*i)->end());
-// }
-//}
diff --git a/library/multithreading.h b/library/multithreading.h
deleted file mode 100644
index 9017bf41..00000000
--- a/library/multithreading.h
+++ /dev/null
@@ -1,41 +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-2010 ZenJu (zhnmju123 AT gmx.de) *
-// **************************************************************************
-//
-#ifndef MULTITHREADING_H_INCLUDED
-#define MULTITHREADING_H_INCLUDED
-
-#include <wx/thread.h>
-
-class StatusHandler;
-class WorkerThread;
-
-
-//class handling execution of a method while updating the UI
-class UpdateWhileExecuting
-{
- friend class WorkerThread;
-
-public:
- UpdateWhileExecuting();
-
- virtual ~UpdateWhileExecuting();
-
- void waitUntilReady();
- void execute(StatusHandler* statusUpdater);
-
-
-private:
- //implement a longrunning method without dependencies (e.g. copy file function); share input/output parameters as instance variables
- virtual void longRunner() = 0;
-
- WorkerThread* theWorkerThread;
-
- wxMutex readyToReceiveResult;
- wxCondition receivingResult;
- bool workDone; //workaround for a bug in wxWidgets v2.8.9 class wxCondition: signals might get lost
-};
-
-#endif // MULTITHREADING_H_INCLUDED
diff --git a/library/pch.h b/library/pch.h
index 1fb71f00..573ae73f 100644
--- a/library/pch.h
+++ b/library/pch.h
@@ -18,6 +18,10 @@ do NOT use in release build!
#define WX_PRECOMP
#endif
+#ifdef _MSC_VER
+#pragma warning(disable:4996) //"warning C4996: 'std::copy': Function call with parameters that may be unsafe"
+#endif
+
#include <wx/wxprec.h>
//#####################################################
diff --git a/library/processXml.cpp b/library/processXml.cpp
index 4ecc0350..c9b641fb 100644
--- a/library/processXml.cpp
+++ b/library/processXml.cpp
@@ -215,7 +215,26 @@ bool readXmlElement(const std::string& name, const TiXmlElement* parent , FreeFi
return true;
}
+ return false;
+}
+
+
+bool readXmlElement(const std::string& name, const TiXmlElement* parent , FreeFileSync::SymLinkHandling& output)
+{
+ std::string dummy;
+ if (xmlAccess::readXmlElement(name, parent, dummy))
+ {
+ if (dummy == "Ignore")
+ output = FreeFileSync::SYMLINK_IGNORE;
+ else if (dummy == "UseDirectly")
+ output = FreeFileSync::SYMLINK_USE_DIRECTLY;
+ else if (dummy == "FollowLink")
+ output = FreeFileSync::SYMLINK_FOLLOW_LINK;
+ else
+ return false;
+ return true;
+ }
return false;
}
@@ -233,7 +252,7 @@ bool readXmlElement(const std::string& name, const TiXmlElement* parent, Zstring
bool readXmlAttribute(const std::string& name, const TiXmlElement* node, xmlAccess::ColumnTypes& output)
{
- int dummy;
+ int dummy = 0;
if (xmlAccess::readXmlAttribute(name, node, dummy))
{
output = static_cast<xmlAccess::ColumnTypes>(dummy);
@@ -303,10 +322,7 @@ void FfsXmlParser::readXmlMainConfig(MainConfiguration& mainCfg)
readXmlElementLogging("FileTimeTolerance", cmpSettings, mainCfg.hidden.fileTimeTolerance);
//include symbolic links at all?
- readXmlElementLogging("IncludeSymlinks", cmpSettings, mainCfg.processSymlinks);
-
- //traverse into symbolic links (to folders)
- readXmlElementLogging("TraverseDirectorySymlinks", cmpSettings, mainCfg.traverseDirectorySymlinks);
+ readXmlElementLogging("HandleSymlinks", cmpSettings, mainCfg.handleSymlinks);
//###########################################################
const TiXmlElement* syncCfg = hRoot.FirstChild("MainConfig").FirstChild("Synchronization").ToElement();
@@ -324,9 +340,6 @@ void FfsXmlParser::readXmlMainConfig(MainConfiguration& mainCfg)
//###########################################################
const TiXmlElement* syncConfig = hRoot.FirstChild("MainConfig").FirstChild("Synchronization").ToElement();
- //copy symbolic links to files
- readXmlElementLogging("CopyFileSymlinks", syncConfig, mainCfg.copyFileSymlinks);
-
//verify file copying
readXmlElementLogging("VerifyCopiedFiles", syncConfig, mainCfg.hidden.verifyFileCopy);
@@ -607,6 +620,23 @@ void addXmlElement(const std::string& name, const FreeFileSync::DeletionPolicy v
}
+void addXmlElement(const std::string& name, const FreeFileSync::SymLinkHandling value, TiXmlElement* parent)
+{
+ switch (value)
+ {
+ case FreeFileSync::SYMLINK_IGNORE:
+ xmlAccess::addXmlElement(name, std::string("Ignore"), parent);
+ break;
+ case FreeFileSync::SYMLINK_USE_DIRECTLY:
+ xmlAccess::addXmlElement(name, std::string("UseDirectly"), parent);
+ break;
+ case FreeFileSync::SYMLINK_FOLLOW_LINK:
+ xmlAccess::addXmlElement(name, std::string("FollowLink"), parent);
+ break;
+ }
+}
+
+
void addXmlElement(const std::string& name, const Zstring& value, TiXmlElement* parent)
{
xmlAccess::addXmlElement(name, wxString(zToWx(value)), parent);
@@ -696,10 +726,7 @@ bool writeXmlMainConfig(const MainConfiguration& mainCfg, TiXmlDocument& doc)
addXmlElement("FileTimeTolerance", mainCfgLocal.hidden.fileTimeTolerance, cmpSettings);
//include symbolic links at all?
- addXmlElement("IncludeSymlinks", mainCfgLocal.processSymlinks, cmpSettings);
-
- //traverse into symbolic links (to folders)
- addXmlElement("TraverseDirectorySymlinks", mainCfgLocal.traverseDirectorySymlinks, cmpSettings);
+ addXmlElement("HandleSymlinks", mainCfgLocal.handleSymlinks, cmpSettings);
//###########################################################
TiXmlElement* syncSettings = new TiXmlElement("Synchronization");
@@ -719,9 +746,6 @@ bool writeXmlMainConfig(const MainConfiguration& mainCfg, TiXmlDocument& doc)
addXmlElement("Conflict", mainCfgLocal.syncConfiguration.conflict, syncDirections);
//###########################################################
- //copy symbolic links to files
- addXmlElement("CopyFileSymlinks", mainCfgLocal.copyFileSymlinks, syncSettings);
-
//verify file copying
addXmlElement("VerifyCopiedFiles", mainCfgLocal.hidden.verifyFileCopy, syncSettings);
diff --git a/library/statistics.cpp b/library/statistics.cpp
index fc140add..3a6970d9 100644
--- a/library/statistics.cpp
+++ b/library/statistics.cpp
@@ -31,11 +31,12 @@ RetrieveStatistics::~RetrieveStatistics()
for (std::vector<statEntry>::const_iterator i = data.begin(); i != data.end(); ++i)
{
- outputFile.Write(FreeFileSync::numberToWxString(static_cast<int>(i->time), false));
+ using globalFunctions::numberToString;
+ outputFile.Write(numberToString(i->time));
outputFile.Write(wxT(";"));
- outputFile.Write(FreeFileSync::numberToWxString(i->objects, false));
+ outputFile.Write(numberToString(i->objects));
outputFile.Write(wxT(";"));
- outputFile.Write(FreeFileSync::numberToWxString(static_cast<int>(i->value), false));
+ outputFile.Write(numberToString(i->value));
outputFile.Write(wxT("\n"));
}
}
@@ -63,6 +64,10 @@ bool isNull(double number)
inline
wxString Statistics::formatRemainingTime(double timeInMs) const
{
+#ifndef _MSC_VER
+#warning adapt units "%x sec"
+#endif
+
bool unitSec = true;
double remainingTime = timeInMs / 1000;
wxString unit = _(" sec");
@@ -83,7 +88,6 @@ wxString Statistics::formatRemainingTime(double timeInMs) const
}
}
-
int formattedTime = globalFunctions::round(remainingTime);
//reduce precision to 5 seconds
@@ -104,7 +108,7 @@ wxString Statistics::formatRemainingTime(double timeInMs) const
}
remainingTimeLast = formattedTime;
- return FreeFileSync::numberToWxString(formattedTime, false) + unit;
+ return globalFunctions::numberToString(formattedTime) + unit;
//+ wxT("(") + globalFunctions::numberToWxString(globalFunctions::round(timeInMs / 1000)) + wxT(")");
}
bgstack15