CP_Main.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152
  1. #include "stdafx.h"
  2. #include "CP_Main.h"
  3. #include "MainFrm.h"
  4. #include "Misc.h"
  5. #include ".\cp_main.h"
  6. #include "server.h"
  7. #include "Client.h"
  8. #include "InternetUpdate.h"
  9. #include <io.h>
  10. #include "Path.h"
  11. #include "Clip_ImportExport.h"
  12. #include "HyperLink.h"
  13. #include "OptionsSheet.h"
  14. #include "DittoCopyBuffer.h"
  15. #include "SendKeys.h"
  16. #include "MainTableFunctions.h"
  17. #include "ShowTaskBarIcon.h"
  18. #ifdef _DEBUG
  19. #define new DEBUG_NEW
  20. #undef THIS_FILE
  21. static char THIS_FILE[] = __FILE__;
  22. #endif
  23. class DittoCommandLineInfo : public CCommandLineInfo
  24. {
  25. public:
  26. DittoCommandLineInfo()
  27. {
  28. m_bDisconnect = FALSE;
  29. m_bConnect = FALSE;
  30. m_uacPID = 0;
  31. m_bOpenWindow = FALSE;
  32. m_bCloseWindow = FALSE;
  33. }
  34. virtual void ParseParam(const TCHAR* pszParam, BOOL bFlag, BOOL bLast)
  35. {
  36. if(bFlag)
  37. {
  38. if(STRICMP(pszParam, _T("Connect")) == 0)
  39. {
  40. m_bConnect = TRUE;
  41. }
  42. else if(STRICMP(pszParam, _T("Disconnect")) == 0)
  43. {
  44. m_bDisconnect = TRUE;
  45. }
  46. else if(wcsncmp(pszParam, _T("uacpaste"), 8) == 0)
  47. {
  48. CString pidCommand(pszParam);
  49. long sep = pidCommand.ReverseFind(':');
  50. if(sep > -1)
  51. {
  52. CString pid = pidCommand.Right(pidCommand.GetLength() - sep - 1);
  53. m_uacPID = ATOI(pid);
  54. }
  55. }
  56. else if(STRICMP(pszParam, _T("open")) == 0)
  57. {
  58. m_bOpenWindow = TRUE;
  59. }
  60. else if(STRICMP(pszParam, _T("close")) == 0)
  61. {
  62. m_bCloseWindow = TRUE;
  63. }
  64. }
  65. CCommandLineInfo::ParseParam(pszParam, bFlag, bLast);
  66. }
  67. BOOL m_bDisconnect;
  68. BOOL m_bConnect;
  69. int m_uacPID;
  70. BOOL m_bCloseWindow;
  71. BOOL m_bOpenWindow;
  72. };
  73. CCP_MainApp theApp;
  74. BEGIN_MESSAGE_MAP(CCP_MainApp, CWinApp)
  75. //{{AFX_MSG_MAP(CCP_MainApp)
  76. // NOTE - the ClassWizard will add and remove mapping macros here.
  77. // DO NOT EDIT what you see in these blocks of generated code!
  78. //}}AFX_MSG_MAP
  79. END_MESSAGE_MAP()
  80. CCP_MainApp::CCP_MainApp()
  81. {
  82. m_copyReason = CopyReasonEnum::COPY_TO_UNKOWN;
  83. m_copyReasonStartTime = 0;
  84. m_activeGroupId = -1;
  85. m_activeGroupStartTime = 0;
  86. m_pUacPasteThread = NULL;
  87. m_bAppRunning = false;
  88. m_bAppExiting = false;
  89. m_connectOnStartup = -1;
  90. m_MainhWnd = NULL;
  91. m_pMainFrame = NULL;
  92. BOOL set = ::AllowSetForegroundWindow(ASFW_ANY);
  93. m_bShowingQuickPaste = false;
  94. m_IC_bCopy = false;
  95. m_GroupDefaultID = 0;
  96. m_GroupID = -1;
  97. m_GroupParentID = 0;
  98. m_GroupText = "History";
  99. m_FocusID = -1;
  100. ClearOldGroupState();
  101. m_bAsynchronousRefreshView = true;
  102. m_lClipsSent = 0;
  103. m_lClipsRecieved = 0;
  104. m_oldtStartUp = COleDateTime::GetCurrentTime();
  105. m_bExitServerThread = false;
  106. m_lLastGoodIndexForNextworkPassword = -2;
  107. m_RTFFormat = ::RegisterClipboardFormat(_T("Rich Text Format"));
  108. m_HTML_Format = ::RegisterClipboardFormat(_T("HTML Format"));
  109. m_PingFormat = ::RegisterClipboardFormat(_T("Ditto Ping Format"));
  110. m_cfIgnoreClipboard = ::RegisterClipboardFormat(_T("Clipboard Viewer Ignore"));
  111. m_cfDelaySavingData = ::RegisterClipboardFormat(_T("Ditto Delay Saving Data"));
  112. m_RemoteCF_HDROP = ::RegisterClipboardFormat(_T("Ditto Remote CF_HDROP"));
  113. m_DittoFileData = ::RegisterClipboardFormat(_T("Ditto File Data"));
  114. m_PNG_Format = GetFormatID(_T("PNG"));
  115. }
  116. CCP_MainApp::~CCP_MainApp()
  117. {
  118. }
  119. BOOL CCP_MainApp::InitInstance()
  120. {
  121. AfxEnableControlContainer();
  122. AfxOleInit();
  123. AfxInitRichEditEx();
  124. Gdiplus::GdiplusStartupInput gdiplusStartupInput;
  125. Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
  126. LoadLibrary(TEXT("MSFTEDIT.DLL"));
  127. //MessageBox(NULL, _T("ditto starting"), _T("d"), MB_OK);
  128. DittoCommandLineInfo cmdInfo;
  129. ParseCommandLine(cmdInfo);
  130. g_Opt.LoadSettings();
  131. theApp.m_activeWnd.TrackActiveWnd(false);
  132. if(cmdInfo.m_uacPID > 0)
  133. {
  134. Log(StrF(_T("Startup up ditto as admin to paste to admin windows, parent process id: %d"), cmdInfo.m_uacPID));
  135. CString mutex;
  136. mutex.Format(_T("DittoAdminPaste_%d"), cmdInfo.m_uacPID);
  137. m_adminPasteMutex = CreateMutex(NULL, FALSE, mutex);
  138. m_pUacPasteThread = new CUAC_Thread(cmdInfo.m_uacPID);
  139. m_pUacPasteThread->Start();
  140. m_pUacPasteThread->WaitForThreadToExit(INT_MAX);
  141. return FALSE;
  142. }
  143. if(cmdInfo.m_strFileName.IsEmpty() == FALSE)
  144. {
  145. try
  146. {
  147. g_Opt.m_bEnableDebugLogging = g_Opt.GetEnableDebugLogging();
  148. CClip_ImportExport Clip;
  149. CppSQLite3DB db;
  150. db.open(cmdInfo.m_strFileName);
  151. CClip_ImportExport clip;
  152. if(clip.ImportFromSqliteDB(db, false, true))
  153. {
  154. ShowCommandLineError("Ditto", theApp.m_Language.GetString("Importing_Good", "Clip placed on clipboard"));
  155. }
  156. else
  157. {
  158. ShowCommandLineError("Ditto", theApp.m_Language.GetString("Error_Importing", "Error importing exported clip"));
  159. }
  160. }
  161. catch (CppSQLite3Exception& e)
  162. {
  163. ASSERT(FALSE);
  164. CString csError;
  165. csError.Format(_T("%s - Exception - %d - %s"), theApp.m_Language.GetString("Error_Parsing", "Error parsing exported clip"), e.errorCode(), e.errorMessage());
  166. ShowCommandLineError("Ditto", csError);
  167. }
  168. return FALSE;
  169. }
  170. else if(cmdInfo.m_bConnect || cmdInfo.m_bDisconnect)
  171. {
  172. //First get the saved hwnd and send it a message
  173. //If ditt is running then this will return 1, meening the running ditto process
  174. //handled this message
  175. //If it didn't handle the message(ditto is not running) then startup this processes of ditto
  176. //disconnected from the clipboard
  177. LRESULT ret = 0;
  178. HWND hWnd = (HWND)CGetSetOptions::GetMainHWND();
  179. if(hWnd)
  180. {
  181. ret = ::SendMessage(hWnd, WM_SET_CONNECTED, cmdInfo.m_bConnect, cmdInfo.m_bDisconnect);
  182. }
  183. //passed off to the running instance of ditto, exit this instance
  184. if(ret == 1)
  185. {
  186. return FALSE;
  187. }
  188. if(cmdInfo.m_bConnect)
  189. {
  190. m_connectOnStartup = TRUE;
  191. }
  192. else if(cmdInfo.m_bDisconnect)
  193. {
  194. m_connectOnStartup = FALSE;
  195. }
  196. }
  197. else if(cmdInfo.m_bOpenWindow || cmdInfo.m_bCloseWindow)
  198. {
  199. //First get the saved hwnd and send it a message
  200. //If ditt is running then this will return 1, meening the running ditto process
  201. //handled this message
  202. //If it didn't handle the message(ditto is not running) then startup this processes of ditto
  203. //disconnected from the clipboard
  204. LRESULT ret = 0;
  205. HWND hWnd = (HWND)CGetSetOptions::GetMainHWND();
  206. if(hWnd)
  207. {
  208. ret = ::SendMessage(hWnd, WM_OPEN_CLOSE_WINDWOW, cmdInfo.m_bOpenWindow, cmdInfo.m_bCloseWindow);
  209. }
  210. return FALSE;
  211. }
  212. CInternetUpdate update;
  213. long lRunningVersion = update.GetRunningVersion();
  214. CString cs = update.GetVersionString(lRunningVersion);
  215. cs.Insert(0, _T("InitInstance - Running Version - "));
  216. Log(cs);
  217. CString csMutex("Ditto Is Now Running");
  218. if(g_Opt.GetIsPortableDitto() || g_Opt.GetIsWindowsApp())
  219. {
  220. csMutex += " ";
  221. csMutex += g_Opt.GetExeFileName();
  222. }
  223. //create mutex doesn't like slashes, remove them, it always returns NULL with them in
  224. csMutex.Replace(_T("\\"), _T("_"));
  225. m_hMutex = CreateMutex(NULL, TRUE, csMutex);
  226. DWORD dwError = GetLastError();
  227. if(m_hMutex == NULL ||
  228. dwError == ERROR_ALREADY_EXISTS)
  229. {
  230. Log(StrF(_T("Ditto is already running, closing, mutex: %s"), csMutex));
  231. HWND hWnd = (HWND)CGetSetOptions::GetMainHWND();
  232. if(hWnd)
  233. ::SendMessage(hWnd, WM_SHOW_TRAY_ICON, TRUE, TRUE);
  234. return TRUE;
  235. }
  236. Log(StrF(_T("Starting up ditto with mutex: %s"), csMutex));
  237. CString csFile = CGetSetOptions::GetLanguageFile();
  238. if(m_Language.LoadLanguageFile(csFile) == false)
  239. {
  240. CString cs;
  241. cs.Format(_T("Error loading language file - %s - \n\n%s"), csFile, m_Language.m_csLastError);
  242. Log(cs);
  243. m_Language.LoadLanguageFile(_T("English.xml"));
  244. }
  245. int nRet = CheckDBExists(CGetSetOptions::GetDBPath());
  246. if(nRet == FALSE)
  247. {
  248. AfxMessageBox(theApp.m_Language.GetString("Error_Opening_Database", "Error Opening Database."));
  249. return FALSE;
  250. }
  251. CMainFrame* pFrame = new CMainFrame;
  252. m_pMainWnd = m_pMainFrame = pFrame;
  253. pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, NULL);
  254. pFrame->ShowWindow(SW_SHOW);
  255. pFrame->UpdateWindow();
  256. return TRUE;
  257. }
  258. void CCP_MainApp::AfterMainCreate()
  259. {
  260. m_MainhWnd = m_pMainFrame->m_hWnd;
  261. ASSERT( ::IsWindow(m_MainhWnd) );
  262. g_Opt.SetMainHWND((long)m_MainhWnd);
  263. g_HotKeys.Init(m_MainhWnd);
  264. // create hotkeys here. They are automatically deleted on exit
  265. m_pDittoHotKey = new CHotKey(CString("DittoHotKey"), 704); //704 is ctrl-tilda
  266. m_pDittoHotKey2 = new CHotKey(CString("DittoHotKey2"));
  267. m_pDittoHotKey3 = new CHotKey(CString("DittoHotKey3"));
  268. m_pPosOne = new CHotKey("Position1", 0, true);
  269. m_pPosTwo = new CHotKey("Position2", 0, true);
  270. m_pPosThree = new CHotKey("Position3", 0, true);
  271. m_pPosFour = new CHotKey("Position4", 0, true);
  272. m_pPosFive = new CHotKey("Position5", 0, true);
  273. m_pPosSix = new CHotKey("Position6", 0, true);
  274. m_pPosSeven = new CHotKey("Position7", 0, true);
  275. m_pPosEight = new CHotKey("Position8", 0, true);
  276. m_pPosNine = new CHotKey("Position9", 0, true);
  277. m_pPosTen = new CHotKey("Position10", 0, true);
  278. m_pCopyBuffer1 = new CHotKey("CopyBufferCopyHotKey_0", 0, true);
  279. m_pPasteBuffer1 = new CHotKey("CopyBufferPasteHotKey_0", 0, true);
  280. m_pCutBuffer1 = new CHotKey("CopyBufferCutHotKey_0", 0, true);
  281. m_pCopyBuffer2 = new CHotKey("CopyBufferCopyHotKey_1", 0, true);
  282. m_pPasteBuffer2 = new CHotKey("CopyBufferPasteHotKey_1", 0, true);
  283. m_pCutBuffer2 = new CHotKey("CopyBufferCutHotKey_1", 0, true);
  284. m_pCopyBuffer3 = new CHotKey("CopyBufferCopyHotKey_2", 0, true);
  285. m_pPasteBuffer3 = new CHotKey("CopyBufferPasteHotKey_2", 0, true);
  286. m_pCutBuffer3 = new CHotKey("CopyBufferCutHotKey_2", 0, true);
  287. m_pTextOnlyPaste = new CHotKey("TextOnlyPaste", 0, true);
  288. m_pSaveClipboard = new CHotKey("SaveClipboard", 0, false);
  289. LoadGlobalClips();
  290. g_HotKeys.RegisterAll();
  291. StartCopyThread();
  292. StartStopServerThread();
  293. #ifdef UNICODE
  294. m_Addins.LoadAll();
  295. #endif
  296. m_bAppRunning = true;
  297. }
  298. void CCP_MainApp::LoadGlobalClips()
  299. {
  300. try
  301. {
  302. {
  303. CppSQLite3Query q = m_db.execQuery(_T("SELECT lID, lShortCut, mText FROM Main WHERE lShortCut > 0 AND globalShortCut = 1"));
  304. while(q.eof() == false)
  305. {
  306. int id = q.getIntField(_T("lID"));
  307. int shortcut = q.getIntField(_T("lShortCut"));
  308. CString desc = q.getStringField(_T("mText"));
  309. //Constructor will add to a global list and free
  310. CHotKey* globalHotKey = new CHotKey(desc, shortcut, true, CHotKey::PASTE_OPEN_CLIP);
  311. if(globalHotKey != NULL)
  312. {
  313. globalHotKey->m_clipId = id;
  314. }
  315. q.nextRow();
  316. }
  317. }
  318. {
  319. CppSQLite3Query q2 = m_db.execQuery(_T("SELECT lID, MoveToGroupShortCut, mText FROM Main WHERE MoveToGroupShortCut > 0 AND GlobalMoveToGroupShortCut = 1"));
  320. while(q2.eof() == false)
  321. {
  322. int id = q2.getIntField(_T("lID"));
  323. int shortcut = q2.getIntField(_T("MoveToGroupShortCut"));
  324. CString desc = q2.getStringField(_T("mText"));
  325. //Constructor will add to a global list and free
  326. CHotKey* globalHotKey = new CHotKey(desc, shortcut, true, CHotKey::MOVE_TO_GROUP);
  327. if(globalHotKey != NULL)
  328. {
  329. globalHotKey->m_clipId = id;
  330. }
  331. q2.nextRow();
  332. }
  333. }
  334. }
  335. CATCH_SQLITE_EXCEPTION
  336. }
  337. void CCP_MainApp::StartStopServerThread()
  338. {
  339. if(CGetSetOptions::GetDisableRecieve() == FALSE && g_Opt.GetAllowFriends())
  340. {
  341. AfxBeginThread(MTServerThread, m_MainhWnd);
  342. }
  343. else
  344. {
  345. m_bExitServerThread = true;
  346. closesocket(theApp.m_sSocket);
  347. }
  348. }
  349. void CCP_MainApp::StopServerThread()
  350. {
  351. m_bExitServerThread = true;
  352. closesocket(theApp.m_sSocket);
  353. }
  354. void CCP_MainApp::BeforeMainClose()
  355. {
  356. ASSERT( m_bAppRunning && !m_bAppExiting );
  357. m_bAppRunning = false;
  358. m_bAppExiting = true;
  359. g_HotKeys.UnregisterAll();
  360. StopServerThread();
  361. StopCopyThread();
  362. }
  363. void CCP_MainApp::StartCopyThread()
  364. {
  365. ASSERT( m_MainhWnd );
  366. CClipTypes* pTypes = LoadTypesFromDB();
  367. // initialize to:
  368. // - m_MainhWnd = send WM_CLIPBOARD_COPIED messages to m_MainhWnd
  369. // - true = use Asynchronous communication (PostMessage)
  370. // - true = enable copying on clipboard changes
  371. // - pTypes = the supported types to use
  372. m_CopyThread.Init(CCopyConfig(m_MainhWnd, true, true, pTypes));
  373. if(m_connectOnStartup == FALSE || g_Opt.GetConnectedToClipboard() == FALSE)
  374. {
  375. m_CopyThread.m_connectOnStartup = false;
  376. Log(StrF(_T("Starting Ditto up disconnected from the clipboard, commandLine: %d, saved value: %d"), m_connectOnStartup, g_Opt.GetConnectedToClipboard()));
  377. SetConnectCV(false);
  378. }
  379. else if(m_connectOnStartup == TRUE)
  380. {
  381. SetConnectCV(true);
  382. Log(_T("Starting Ditto up connected from the clipboard, passed in true from command line to start connected"));
  383. }
  384. VERIFY(m_CopyThread.CreateThread(CREATE_SUSPENDED));
  385. m_CopyThread.ResumeThread();
  386. }
  387. void CCP_MainApp::StopCopyThread()
  388. {
  389. EnableCbCopy(false);
  390. m_CopyThread.Quit();
  391. }
  392. // returns the current Clipboard Viewer Connect state (though it might not yet
  393. // be actually connected -- check IsClipboardViewerConnected())
  394. bool CCP_MainApp::ToggleConnectCV()
  395. {
  396. bool bConnect = !GetConnectCV();
  397. SetConnectCV(bConnect);
  398. return bConnect;
  399. }
  400. // Sets a menu entry according to the current Clipboard Viewer Connection status
  401. // - the menu text indicates the available command (opposite the current state)
  402. // - a check mark appears in the rare cases that the menu text actually represents
  403. // the current state, e.g. if we are supposed to be connected, but we somehow
  404. // lose that connection, "Disconnect from Clipboard" will have a check next to it.
  405. void CCP_MainApp::UpdateMenuConnectCV(CMenu* pMenu, UINT nMenuID)
  406. {
  407. if(pMenu == NULL)
  408. return;
  409. bool bConnect = theApp.GetConnectCV();
  410. CString cs;
  411. if(bConnect)
  412. {
  413. cs = theApp.m_Language.GetString("Disconnect_Clipboard", "Disconnect from Clipboard.");
  414. pMenu->ModifyMenu(nMenuID, MF_BYCOMMAND, nMenuID, cs);
  415. }
  416. else
  417. {
  418. cs = theApp.m_Language.GetString("Connect_Clipboard", "Connect to Clipboard.");
  419. pMenu->ModifyMenu(nMenuID, MF_BYCOMMAND, nMenuID, cs);
  420. }
  421. }
  422. // Allocates a new CClipTypes
  423. CClipTypes* CCP_MainApp::LoadTypesFromDB()
  424. {
  425. CClipTypes* pTypes = new CClipTypes;
  426. try
  427. {
  428. CppSQLite3Query q = theApp.m_db.execQuery(_T("SELECT TypeText FROM Types"));
  429. while(q.eof() == false)
  430. {
  431. pTypes->Add(GetFormatID(q.getStringField(_T("TypeText"))));
  432. q.nextRow();
  433. }
  434. }
  435. CATCH_SQLITE_EXCEPTION
  436. if(pTypes->GetSize() <= 0)
  437. {
  438. pTypes->Add(CF_TEXT);
  439. pTypes->Add(RegisterClipboardFormat(CF_RTF));
  440. pTypes->Add(CF_UNICODETEXT);
  441. pTypes->Add(CF_HDROP);
  442. pTypes->Add(CF_DIB);
  443. }
  444. return pTypes;
  445. }
  446. void CCP_MainApp::ReloadTypes()
  447. {
  448. CClipTypes* pTypes = LoadTypesFromDB();
  449. if(pTypes)
  450. {
  451. m_CopyThread.SetSupportedTypes(pTypes);
  452. }
  453. }
  454. void CCP_MainApp::RefreshView()
  455. {
  456. CQPasteWnd *pWnd = QPasteWnd();
  457. if(pWnd)
  458. {
  459. if(m_bAsynchronousRefreshView)
  460. {
  461. pWnd->PostMessage(WM_REFRESH_VIEW);
  462. }
  463. else
  464. {
  465. pWnd->SendMessage(WM_REFRESH_VIEW);
  466. }
  467. }
  468. }
  469. void CCP_MainApp::RefreshClipAfterPaste(int clipId, int updateFlags)
  470. {
  471. CQPasteWnd *pWnd = QPasteWnd();
  472. if(pWnd)
  473. {
  474. if(m_bAsynchronousRefreshView)
  475. {
  476. pWnd->PostMessage(WM_RELOAD_CLIP_AFTER_PASTE, clipId, updateFlags);
  477. }
  478. else
  479. {
  480. pWnd->SendMessage(WM_RELOAD_CLIP_AFTER_PASTE, clipId, updateFlags);
  481. }
  482. }
  483. }
  484. void CCP_MainApp::OnPasteCompleted()
  485. {
  486. }
  487. void CCP_MainApp::OnCopyCompleted(long lLastID, int count)
  488. {
  489. if(count <= 0)
  490. {
  491. return;
  492. }
  493. // update copy statistics
  494. CGetSetOptions::SetTripCopyCount(-count);
  495. CGetSetOptions::SetTotalCopyCount(-count);
  496. if(m_CopyBuffer.Active())
  497. {
  498. m_CopyBuffer.EndCopy(lLastID);
  499. }
  500. RefreshView();
  501. }
  502. // Internal Clipboard for cut/copy/paste items between Groups
  503. // if NULL, this uses the current QPaste selection
  504. void CCP_MainApp::IC_Cut(ARRAY* pIDs)
  505. {
  506. if(pIDs == NULL)
  507. {
  508. if(QPasteWnd())
  509. {
  510. QPasteWnd()->m_lstHeader.GetSelectionItemData(m_IC_IDs);
  511. }
  512. else
  513. {
  514. m_IC_IDs.SetSize(0);
  515. }
  516. }
  517. else
  518. {
  519. m_IC_IDs.Copy(*pIDs);
  520. }
  521. m_IC_bCopy = false;
  522. if(QPasteWnd())
  523. {
  524. QPasteWnd()->UpdateStatus();
  525. }
  526. }
  527. // if NULL, this uses the current QPaste selection
  528. void CCP_MainApp::IC_Copy(ARRAY* pIDs)
  529. {
  530. if(pIDs == NULL)
  531. {
  532. if(QPasteWnd())
  533. {
  534. QPasteWnd()->m_lstHeader.GetSelectionItemData(m_IC_IDs);
  535. }
  536. else
  537. {
  538. m_IC_IDs.SetSize(0);
  539. }
  540. }
  541. else
  542. {
  543. m_IC_IDs.Copy(*pIDs);
  544. }
  545. m_IC_bCopy = true;
  546. RefreshView();
  547. }
  548. void CCP_MainApp::IC_Paste()
  549. {
  550. if(m_IC_IDs.GetSize() <= 0)
  551. {
  552. return;
  553. }
  554. if(m_IC_bCopy)
  555. {
  556. m_IC_IDs.CopyTo(GetValidGroupID());
  557. }
  558. else // Move
  559. {
  560. m_IC_IDs.MoveTo(GetValidGroupID());
  561. }
  562. // don't process the same items twice.
  563. m_IC_IDs.SetSize(0);
  564. RefreshView();
  565. }
  566. // Groups
  567. void CCP_MainApp::SaveCurrentGroupState()
  568. {
  569. m_oldGroupID = m_GroupID;
  570. m_oldGroupParentID = m_GroupParentID;
  571. m_oldGroupText = m_GroupText;
  572. }
  573. void CCP_MainApp::ClearOldGroupState()
  574. {
  575. m_oldGroupID = -2;
  576. m_oldGroupParentID = -2;
  577. m_oldGroupText = _T("");
  578. }
  579. BOOL CCP_MainApp::TryEnterOldGroupState()
  580. {
  581. BOOL enteredGroup = FALSE;
  582. if(m_oldGroupID > -2)
  583. {
  584. m_GroupID = m_oldGroupID;
  585. m_GroupParentID = m_oldGroupParentID;
  586. m_GroupText = m_oldGroupText;
  587. ClearOldGroupState();
  588. theApp.RefreshView();
  589. if(QPasteWnd())
  590. QPasteWnd()->UpdateStatus(true);
  591. enteredGroup = TRUE;
  592. }
  593. return enteredGroup;
  594. }
  595. BOOL CCP_MainApp::EnterGroupID(long lID, BOOL clearOldGroupState/* = TRUE*/, BOOL saveCurrentGroupState/* = FALSE*/)
  596. {
  597. BOOL bResult = FALSE;
  598. if(m_GroupID == lID)
  599. return TRUE;
  600. DWORD startTick = GetTickCount();
  601. if(clearOldGroupState)
  602. {
  603. ClearOldGroupState();
  604. }
  605. if(saveCurrentGroupState)
  606. {
  607. SaveCurrentGroupState();
  608. }
  609. // if we are switching to the parent, focus on the previous group
  610. if(m_GroupParentID == lID && m_GroupID > 0)
  611. m_FocusID = m_GroupID;
  612. switch(lID)
  613. {
  614. case -1:
  615. m_FocusID = -1;
  616. m_GroupID = -1;
  617. m_GroupParentID = -1;
  618. m_GroupText = "History";
  619. bResult = TRUE;
  620. break;
  621. default: // Normal Group
  622. try
  623. {
  624. CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT lParentID, mText, bIsGroup FROM Main WHERE lID = %d"), lID);
  625. if(q.eof() == false)
  626. {
  627. if(q.getIntField(_T("bIsGroup")) > 0)
  628. {
  629. m_GroupID = lID;
  630. m_GroupParentID = q.getIntField(_T("lParentID"));
  631. m_GroupText = q.getStringField(_T("mText"));
  632. bResult = TRUE;
  633. }
  634. }
  635. }
  636. CATCH_SQLITE_EXCEPTION
  637. break;
  638. }
  639. if(bResult)
  640. {
  641. theApp.RefreshView();
  642. if(QPasteWnd())
  643. QPasteWnd()->UpdateStatus(true);
  644. }
  645. DWORD endTick = GetTickCount();
  646. if((endTick-startTick) > 150)
  647. Log(StrF(_T("Paste Timing EnterParentId: %d"), endTick-startTick));
  648. return bResult;
  649. }
  650. // returns a usable group id (not negative)
  651. long CCP_MainApp::GetValidGroupID()
  652. {
  653. return m_GroupID;
  654. }
  655. // sets a valid id
  656. void CCP_MainApp::SetGroupDefaultID(long lID)
  657. {
  658. if(m_GroupDefaultID == lID)
  659. {
  660. return;
  661. }
  662. if(lID <= 0)
  663. {
  664. m_GroupDefaultID = 0;
  665. }
  666. else
  667. {
  668. m_GroupDefaultID = lID;
  669. }
  670. if(QPasteWnd())
  671. {
  672. QPasteWnd()->UpdateStatus();
  673. }
  674. }
  675. void CCP_MainApp::SetStatus(const TCHAR* status, bool bRepaintImmediately)
  676. {
  677. m_Status = status;
  678. if(QPasteWnd())
  679. {
  680. QPasteWnd()->UpdateStatus(bRepaintImmediately);
  681. }
  682. }
  683. void CCP_MainApp::ShowPersistent(bool bVal)
  684. {
  685. g_Opt.SetShowPersistent(bVal);
  686. // give some visual indication
  687. if(m_bShowingQuickPaste)
  688. {
  689. ASSERT(QPasteWnd());
  690. QPasteWnd()->SetCaptionColorActive(g_Opt.m_bShowPersistent, theApp.GetConnectCV());
  691. QPasteWnd()->RefreshNc();
  692. }
  693. }
  694. /////////////////////////////////////////////////////////////////////////////
  695. // CCP_MainApp message handlers
  696. int CCP_MainApp::ExitInstance()
  697. {
  698. Log(_T("ExitInstance"));
  699. DeleteDittoTempFiles(FALSE);
  700. m_db.close();
  701. if(m_pUacPasteThread != NULL)
  702. {
  703. if(m_pUacPasteThread->ThreadWasStarted() == false)
  704. {
  705. m_pUacPasteThread->FireExit();
  706. }
  707. delete m_pUacPasteThread;
  708. }
  709. Gdiplus::GdiplusShutdown(m_gdiplusToken);
  710. return CWinApp::ExitInstance();
  711. }
  712. // return TRUE if there is more idle processing to do
  713. BOOL CCP_MainApp::OnIdle(LONG lCount)
  714. {
  715. // let winapp handle its idle processing
  716. if(CWinApp::OnIdle(lCount))
  717. return TRUE;
  718. return FALSE;
  719. }
  720. void CCP_MainApp::SetConnectCV(bool bConnect)
  721. {
  722. m_CopyThread.SetConnectCV(bConnect);
  723. g_Opt.SetConnectedToClipboard(bConnect == true);
  724. if(bConnect)
  725. {
  726. m_pMainFrame->m_trayIcon.SetIcon(IDR_MAINFRAME);
  727. m_pMainFrame->m_trayIcon.SetTooltipText(_T("Ditto"));
  728. }
  729. else
  730. {
  731. m_pMainFrame->m_trayIcon.SetIcon(IDI_DITTO_NOCOPYCB);
  732. CString cs;
  733. cs = _T("Ditto ");
  734. cs += theApp.m_Language.GetString("disconnected", "[Disconnected]");
  735. m_pMainFrame->m_trayIcon.SetTooltipText(cs);
  736. }
  737. if(QPasteWnd())
  738. {
  739. QPasteWnd()->SetCaptionColorActive(g_Opt.m_bShowPersistent, theApp.GetConnectCV());
  740. QPasteWnd()->RefreshNc();
  741. }
  742. }
  743. void CCP_MainApp::OnDeleteID(long lID)
  744. {
  745. if(QPasteWnd())
  746. {
  747. QPasteWnd()->PostMessage(NM_ITEM_DELETED, lID, 0);
  748. }
  749. }
  750. bool CCP_MainApp::ImportClips(HWND hWnd)
  751. {
  752. OPENFILENAME FileName;
  753. TCHAR szFileName[400];
  754. TCHAR szDir[400];
  755. memset(&FileName, 0, sizeof(FileName));
  756. memset(szFileName, 0, sizeof(szFileName));
  757. memset(&szDir, 0, sizeof(szDir));
  758. CString csInitialDir = CGetSetOptions::GetLastImportDir();
  759. STRCPY(szDir, csInitialDir);
  760. FileName.lStructSize = sizeof(FileName);
  761. FileName.lpstrTitle = _T("Import Clips");
  762. FileName.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR;
  763. FileName.nMaxFile = 400;
  764. FileName.lpstrFile = szFileName;
  765. FileName.lpstrInitialDir = szDir;
  766. FileName.lpstrFilter = _T("Exported Ditto Clips (.dto)\0*.dto\0\0");
  767. FileName.lpstrDefExt = _T("dto");
  768. if(GetOpenFileName(&FileName) == 0)
  769. {
  770. return false;
  771. }
  772. using namespace nsPath;
  773. CPath path(FileName.lpstrFile);
  774. CString csPath = path.GetPath();
  775. CGetSetOptions::SetLastImportDir(csPath);
  776. try
  777. {
  778. CppSQLite3DB db;
  779. db.open(FileName.lpstrFile);
  780. CClip_ImportExport clip;
  781. if(clip.ImportFromSqliteDB(db, true, false))
  782. {
  783. CShowTaskBarIcon show;
  784. CString cs;
  785. cs.Format(_T("%s %d "), theApp.m_Language.GetString("Import_Successfully", "Successfully imported"), clip.m_importCount);
  786. if(clip.m_importCount = 1)
  787. cs += theApp.m_Language.GetString("Clip", "clip");
  788. else
  789. cs += theApp.m_Language.GetString("Clips", "clips");
  790. MessageBox(hWnd, cs, _T("Ditto"), MB_OK);
  791. }
  792. else
  793. {
  794. CShowTaskBarIcon show;
  795. MessageBox(hWnd, theApp.m_Language.GetString("Error_Importing", "Error importing exported clip"), _T("Ditto"), MB_OK);
  796. }
  797. }
  798. catch (CppSQLite3Exception& e)
  799. {
  800. ASSERT(FALSE);
  801. CString csError;
  802. csError.Format(_T("%s - Exception - %d - %s"), theApp.m_Language.GetString("Error_Parsing", "Error parsing exported clip"), e.errorCode(), e.errorMessage());
  803. MessageBox(hWnd, csError, _T("Ditto"), MB_OK);
  804. }
  805. return true;
  806. }
  807. void CCP_MainApp::ShowCommandLineError(CString csTitle, CString csMessage)
  808. {
  809. Log(StrF(_T("ShowCommandLineError %s - %s"), csTitle, csMessage));
  810. CToolTipEx *pErrorWnd = new CToolTipEx;
  811. pErrorWnd->Create(NULL);
  812. pErrorWnd->SetToolTipText(csTitle + "\n\n" + csMessage);
  813. CPoint pt;
  814. CRect rcScreen;
  815. GetMonitorRect(0, &rcScreen);
  816. pt = rcScreen.BottomRight();
  817. CRect cr = pErrorWnd->GetBoundsRect();
  818. pt.x -= max(cr.Width()+50, 150);
  819. pt.y -= max(cr.Height()+50, 150);
  820. pErrorWnd->Show(pt);
  821. Sleep(4000);
  822. pErrorWnd->DestroyWindow();
  823. }
  824. BOOL CCP_MainApp::GetClipData(long parentId, CClipFormat &Clip)
  825. {
  826. BOOL bRet = FALSE;
  827. try
  828. {
  829. CppSQLite3Query q = theApp.m_db.execQueryEx(_T("SELECT ooData FROM Data WHERE lParentID = %d AND strClipboardFormat = '%s'"), parentId, GetFormatName(Clip.m_cfType));
  830. if(q.eof() == false)
  831. {
  832. int nDataLen = 0;
  833. const unsigned char *cData = q.getBlobField(_T("ooData"), nDataLen);
  834. if(cData != NULL)
  835. {
  836. Clip.m_hgData = NewGlobal(nDataLen);
  837. ::CopyToGlobalHP(Clip.m_hgData, (LPVOID)cData, nDataLen);
  838. bRet = TRUE;
  839. }
  840. }
  841. }
  842. CATCH_SQLITE_EXCEPTION
  843. return bRet;
  844. }
  845. bool CCP_MainApp::EditItems(CClipIDs &Ids, bool bShowError)
  846. {
  847. m_pMainFrame->ShowEditWnd(Ids);
  848. return true;
  849. }
  850. void CCP_MainApp::PumpMessageEx(HWND hWnd)
  851. {
  852. MSG KeyboardMsg;
  853. while (::PeekMessage(&KeyboardMsg, hWnd, 0, 0, PM_REMOVE))
  854. {
  855. ::TranslateMessage(&KeyboardMsg);
  856. ::DispatchMessage(&KeyboardMsg);
  857. }
  858. }
  859. HWND CCP_MainApp::QPastehWnd()
  860. {
  861. if(m_pMainFrame != NULL)
  862. {
  863. if(m_pMainFrame->m_quickPaste.m_pwndPaste != NULL)
  864. {
  865. return m_pMainFrame->m_quickPaste.m_pwndPaste->GetSafeHwnd();
  866. }
  867. }
  868. return NULL;
  869. }
  870. CQPasteWnd* CCP_MainApp::QPasteWnd()
  871. {
  872. if(m_pMainFrame != NULL)
  873. {
  874. return m_pMainFrame->m_quickPaste.m_pwndPaste;
  875. }
  876. return NULL;
  877. }
  878. bool CCP_MainApp::UACPaste()
  879. {
  880. if(m_pUacPasteThread == NULL)
  881. {
  882. m_pUacPasteThread = new CUAC_Thread(GetCurrentProcessId());
  883. }
  884. return m_pUacPasteThread->UACPaste();
  885. }
  886. bool CCP_MainApp::UACCopy()
  887. {
  888. if(m_pUacPasteThread == NULL)
  889. {
  890. m_pUacPasteThread = new CUAC_Thread(GetCurrentProcessId());
  891. }
  892. return m_pUacPasteThread->UACCopy();
  893. }
  894. bool CCP_MainApp::UACCut()
  895. {
  896. if(m_pUacPasteThread == NULL)
  897. {
  898. m_pUacPasteThread = new CUAC_Thread(GetCurrentProcessId());
  899. }
  900. return m_pUacPasteThread->UACCut();
  901. }
  902. bool CCP_MainApp::UACThreadRunning()
  903. {
  904. if(m_pUacPasteThread != NULL)
  905. {
  906. return m_pUacPasteThread->IsRunning();
  907. }
  908. return false;
  909. }
  910. void CCP_MainApp::RefreshShowInTaskBar()
  911. {
  912. if(m_pMainFrame != NULL)
  913. {
  914. m_pMainFrame->RefreshShowInTaskBar();
  915. }
  916. }
  917. void CCP_MainApp::SetActiveGroupId(int groupId)
  918. {
  919. m_activeGroupId = groupId;
  920. m_activeGroupStartTime = GetTickCount();
  921. }
  922. int CCP_MainApp::GetActiveGroupId()
  923. {
  924. int ret = -1;
  925. DWORD maxDiff = CGetSetOptions::GetSaveToGroupTimeoutMS();
  926. DWORD diff = GetTickCount() - m_activeGroupStartTime;
  927. if(m_activeGroupId > -1 &&
  928. diff < maxDiff)
  929. {
  930. ret = m_activeGroupId;
  931. }
  932. m_activeGroupId = -1;
  933. m_activeGroupStartTime = 0;
  934. return ret;
  935. }
  936. void CCP_MainApp::SetCopyReason(CopyReasonEnum::CopyReason copyReason)
  937. {
  938. m_copyReason = copyReason;
  939. m_copyReasonStartTime = GetTickCount();
  940. }
  941. CopyReasonEnum::CopyReason CCP_MainApp::GetCopyReason()
  942. {
  943. CopyReasonEnum::CopyReason ret = CopyReasonEnum::COPY_TO_UNKOWN;
  944. DWORD maxDiff = CGetSetOptions::GetCopyReasonTimeoutMS();
  945. DWORD diff = GetTickCount() - m_copyReasonStartTime;
  946. if(m_copyReason != CopyReasonEnum::COPY_TO_UNKOWN &&
  947. diff < maxDiff)
  948. {
  949. ret = m_copyReason;
  950. }
  951. m_copyReason = CopyReasonEnum::COPY_TO_UNKOWN;
  952. m_copyReasonStartTime = 0;
  953. return ret;
  954. }