Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/AdvGeneral.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ END_MESSAGE_MAP()
#define SETTING_HIDE_TASKBAR_ICON_ON_CLOSE 109
#define SETTING_USE_MODERN_SCROLLBAR 110
#define SETTING_ENFORCE_CLIPBOARD_IGNORE_FORMATS 111
#define SETTING_EXPIRED_IMAGE_DAYS 112

BOOL CAdvGeneral::OnInitDialog()
{
Expand Down Expand Up @@ -217,6 +218,8 @@ BOOL CAdvGeneral::OnInitDialog()
pGroupTest->AddSubItem(new CMFCPropertyGridProperty(_T("Default paste string"), CGetSetOptions::GetDefaultPasteString(), _T(""), SETTING_DEFAULT_PASTE_STRING));
pGroupTest->AddSubItem(new CMFCPropertyGridProperty(_T("Default copy string"), CGetSetOptions::GetDefaultCopyString(), _T(""), SETTING_DEFAULT_COPY_STRING));
pGroupTest->AddSubItem(new CMFCPropertyGridProperty(_T("Default cut string"), CGetSetOptions::GetDefaultCutString(), _T(""), SETTING_DEFAULT_CUT_STRING));

pGroupTest->AddSubItem(new CMFCPropertyGridProperty(_T("Delete images (CF_DIB, PNG) from clips not used in x days (0 = never)"), CGetSetOptions::GetExpiredImageDays(), _T("Removes CF_DIB, CF_DIBV5 and PNG data from clips that have not been used in this many days, other formats of the clip are kept. Clips that only contain image data are deleted. Clips with shortcuts, in groups, sticky or set to never auto delete are not affected."), SETTING_EXPIRED_IMAGE_DAYS));

static TCHAR BASED_CODE szDiffFilter[] = _T("Diff Applications(*.exe)|*.exe||");
CMFCPropertyGridFileProperty* pDiffProp = new CMFCPropertyGridFileProperty(_T("Diff application path"), TRUE, CGetSetOptions::GetDiffApp(), _T("exe"), 0, szDiffFilter, (LPCTSTR)0, SETTING_DIFF_APP);
Expand Down Expand Up @@ -999,6 +1002,12 @@ void CAdvGeneral::OnBnClickedOk()
CGetSetOptions::SetEnforceClipboardIgnoreFormats(val);
}
break;
case SETTING_EXPIRED_IMAGE_DAYS:
if (pNewValue->lVal != pOrigValue->lVal)
{
CGetSetOptions::SetExpiredImageDays(max(pNewValue->lVal, 0));
}
break;
}
}
}
Expand Down
70 changes: 70 additions & 0 deletions src/DatabaseUtilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,74 @@ BOOL RepairDatabase()
return TRUE;
}

//Images are by far the largest items in the database, remove the image formats from clips that have not been used
//in the set number of days. Other formats of the clip are kept, clips that only had image data are deleted.
static void RemoveExpiredImages(CppSQLite3DB &db, bool checkIdleTime)
{
long expireDays = CGetSetOptions::GetExpiredImageDays();
if (expireDays <= 0)
return;

//deleting large blobs can lock the db for a while, only do it when idle and in batches
if (checkIdleTime && IdleSeconds() <= CGetSetOptions::GetIdleSecondsBeforeDelete())
{
Log(_T("Computer has not been idle long enough to remove expired images"));
return;
}

CTime expireTime = CTime::GetCurrentTime();
expireTime -= CTimeSpan(expireDays, 0, 0, 0);

const TCHAR *imageFormats = _T("'CF_DIB', 'CF_DIBV5', 'PNG'");

std::vector<int> clipIds;
{
CppSQLite3Query q = db.execQueryEx(_T("SELECT DISTINCT Main.lID FROM Main ")
_T("INNER JOIN Data ON Data.lParentID = Main.lID ")
_T("WHERE Main.lastPasteDate < %d AND Data.strClipBoardFormat IN (%s) AND ")
_T("Main.bIsGroup = 0 AND Main.lShortCut = 0 AND Main.lParentID <= 0 AND Main.lDontAutoDelete = 0 AND Main.stickyClipOrder = -(2147483647) AND Main.stickyClipGroupOrder = -(2147483647) ")
_T("LIMIT %d"), (int)expireTime.GetTime(), imageFormats, CGetSetOptions::GetMainDeletesDeleteCount());

while (q.eof() == false)
{
clipIds.push_back(q.getIntField(_T("lID")));
q.nextRow();
}
}

CClipIDs emptyClipIds;
std::vector<int> changedClipIds;

for (int clipId : clipIds)
{
int deleteCount = db.execDMLEx(_T("DELETE FROM Data WHERE lParentID = %d AND strClipBoardFormat IN (%s)"), clipId, imageFormats);

Log(StrF(_T("From Images Expire - Deleted %d image formats from Id: %d"), deleteCount, clipId));

if (db.execScalarEx(_T("SELECT COUNT(lID) FROM Data WHERE lParentID = %d"), clipId) == 0)
{
emptyClipIds.Add(clipId);
}
else
{
//the clip no longer holds everything that was copied, clear the CRC so copying the
//same thing again adds a new clip with the image rather than moving this one to the top
db.execDMLEx(_T("UPDATE Main SET CRC = 0 WHERE lID = %d"), clipId);
changedClipIds.push_back(clipId);
}
}

if (emptyClipIds.GetCount() > 0)
{
emptyClipIds.DeleteIDs(false, db);
}

for (int clipId : changedClipIds)
{
theApp.RefreshClipInUI(clipId, UPDATE_CLIP_DESCRIPTION);
}
}

BOOL RemoveOldEntries(bool checkIdleTime)
{
Log(StrF(_T("Beginning of RemoveOldEntries MaxEntries: %d - Keep days: %d"), CGetSetOptions::GetMaxEntries(), CGetSetOptions::GetExpiredEntries()));
Expand Down Expand Up @@ -921,6 +989,8 @@ BOOL RemoveOldEntries(bool checkIdleTime)
}
}

RemoveExpiredImages(db, checkIdleTime);

int toDeleteCount = db.execScalar(_T("SELECT COUNT(clipID) FROM MainDeletes"));

Log(StrF(_T("Before Deleting emptied out data, count: %d, Idle Seconds: %f"), toDeleteCount, IdleSeconds()));
Expand Down
10 changes: 10 additions & 0 deletions src/Options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,16 @@ long CGetSetOptions::GetExpiredEntries()
return GetProfileLong("ExpiredEntries", 5);
}

void CGetSetOptions::SetExpiredImageDays(long lVal)
{
SetProfileLong("ExpiredImageDays", lVal);
}

long CGetSetOptions::GetExpiredImageDays()
{
return GetProfileLong("ExpiredImageDays", 0);
}

void CGetSetOptions::SetTripCopyCount(long lVal)
{
// negative means a relative offset
Expand Down
3 changes: 3 additions & 0 deletions src/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ class CGetSetOptions
static void SetExpiredEntries(long lVal);
static long GetExpiredEntries();

static void SetExpiredImageDays(long lVal);
static long GetExpiredImageDays();

static void SetTripCopyCount(long lVal);
static long GetTripCopyCount();

Expand Down