1e1a2e7d21c97bf32df10899aa90ccd04adfeddb
[reactos.git] / subsys / system / explorer / Seashell / SeaShellExt / cbformats.cpp
1 //*******************************************************************************
2 // COPYRIGHT NOTES
3 // ---------------
4 // You may use this source code, compile or redistribute it as part of your application 
5 // for free. You cannot redistribute it as a part of a software development 
6 // library without the agreement of the author. If the sources are 
7 // distributed along with the application, you should leave the original 
8 // copyright notes in the source code without any changes.
9 // This code can be used WITHOUT ANY WARRANTIES at your own risk.
10 // 
11 // For the latest updates to this code, check this site:
12 // http://www.masmex.com 
13 // after Sept 2000
14 // 
15 // Copyright(C) 2000 Philip Oldaker <email: philip@masmex.com>
16 //*******************************************************************************
17
18 #include "stdafx.h"
19 #include "cbformats.h"
20 #include "shlobj.h"
21 #include "ShellPidl.h"
22 #include <afxpriv.h>
23
24 #ifdef _DEBUG
25 #define new DEBUG_NEW
26 #undef THIS_FILE
27 static char THIS_FILE[] = __FILE__;
28 #endif
29
30 //static
31 CWDClipboardData *CWDClipboardData::Instance()
32 {
33         static CWDClipboardData data;
34         return &data;
35 }
36
37 CWDClipboardData::CWDClipboardData()
38 {
39         m_aFormatIDs[e_cfString] = CF_TEXT;
40         m_aFormatIDs[e_cfHDROP] = CF_HDROP;
41         m_aFormatIDs[e_cfWebSiteURL] = ::RegisterClipboardFormat(CFSTR_SHELLURL);
42 #ifdef _UNICODE
43         m_aFormatIDs[e_cfFileGroupDesc] = ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
44 #else
45         m_aFormatIDs[e_cfFileGroupDesc] = ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
46 #endif
47         m_aFormatIDs[e_cfHTMLFormat] = ::RegisterClipboardFormat(_T("HTML Format"));
48         m_aFormatIDs[e_cfWebSite] = ::RegisterClipboardFormat(_T("CF_WD_WEBSITE"));
49         m_aFormatIDs[e_cfRightMenu] = ::RegisterClipboardFormat(_T("CF_WD_RIGHTMENU"));
50         m_aFormatIDs[e_cfFolder] = ::RegisterClipboardFormat(_T("CF_WD_WEBSITE_CATEGORY"));
51         m_aFormatIDs[e_cfShellIDList] = ::RegisterClipboardFormat(CFSTR_SHELLIDLIST);
52 }
53
54 CWDClipboardData::~CWDClipboardData()
55 {
56 }
57
58 bool CWDClipboardData::IsValidFormat(CLIPFORMAT cfFormat)
59 {
60         for(int i=0;i < e_cfMax;i++)
61         {
62                 if (m_aFormatIDs[i] == cfFormat)
63                         break;
64         }
65         return(i != e_cfMax);
66 }
67
68 bool CWDClipboardData::IsDataAvailable(COleDataObject *pDataObject)
69 {
70         // Iterate through the clipboard formats
71         pDataObject->BeginEnumFormats();
72         FORMATETC FormatEtc;
73         bool bFound=false;
74 #ifdef _DEBUG
75         TCHAR szBuf[128];
76 #endif
77         while (pDataObject->GetNextFormat(&FormatEtc))
78         {
79 #ifdef _DEBUG
80                 szBuf[0] = 0;
81                 if (FormatEtc.cfFormat > CF_MAX)
82                 {
83                         ::GetClipboardFormatName(FormatEtc.cfFormat,szBuf,sizeof(szBuf)-1);
84                 }
85                 else
86                 {
87                         lstrcpy(szBuf,_T("Predefined Format"));
88                 }
89                 TRACE(_T("Enum formats returned %u(%s) %d\n"),FormatEtc.cfFormat,szBuf,FormatEtc.tymed);
90 #endif
91                 if (IsValidFormat(FormatEtc.cfFormat))
92                 {
93 #ifdef _DEBUG
94                         TRACE(_T("Clipboard format found %u(%s) tymed(%d), Aspect(%d)\n"),FormatEtc.cfFormat,szBuf,FormatEtc.tymed,FormatEtc.dwAspect);
95 #endif
96                         bFound=true;
97                 }
98         }       
99         return bFound;
100 }
101
102 CLIPFORMAT CWDClipboardData::GetClipboardFormat(eCBFormats format)
103 {
104         return m_aFormatIDs[format]; 
105 }
106
107 void CWDClipboardData::SetData(COleDataSource *pOleDataSource,CObject *pObj,eCBFormats format,LPFORMATETC lpFormatEtc)
108 {
109         ASSERT(pOleDataSource);
110         ASSERT(pObj);
111
112         // use serialization
113         CSharedFile file;
114         CArchive ar(&file,CArchive::store);
115         pObj->Serialize(ar);
116         ar.Close();
117
118         // cache into drag drop source
119         pOleDataSource->CacheGlobalData(CWDClipboardData::Instance()->GetClipboardFormat(format),file.Detach(),lpFormatEtc);            
120 }
121
122 bool CWDClipboardData::GetData(COleDataObject *pDataObject,CObject *pObj,eCBFormats format)
123 {
124         ASSERT(pDataObject);
125         ASSERT(pObj);
126         if (pDataObject == NULL || pObj == NULL)
127                 return false;
128
129         if (m_aFormatIDs[format] == CF_HDROP)
130         {
131                 FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
132                 STGMEDIUM medium;
133                 if (pDataObject->GetData(CF_HDROP, &medium, &fmte))
134                 {
135                         HDROP hDropInfo = (HDROP)medium.hGlobal;
136                         UINT wNumFilesDropped = DragQueryFile(hDropInfo, 0XFFFFFFFF, NULL, 0);
137                         TCHAR szFile[MAX_PATH];
138                         ASSERT_KINDOF(CCF_HDROP,pObj);
139                         CCF_HDROP *pHDROP = (CCF_HDROP*)pObj;
140                         UINT nLen;
141                         for(UINT i=0; i < wNumFilesDropped;i++)
142                         {
143                                 nLen = DragQueryFile(hDropInfo,i,szFile,sizeof(szFile)/sizeof(TCHAR));
144                                 if (nLen)
145                                 {
146                                         pHDROP->AddFileName(szFile);
147                                 }
148                         }
149                         if (medium.pUnkForRelease)
150                                 medium.pUnkForRelease->Release();
151                         else
152                                 GlobalFree(medium.hGlobal);
153                 }
154         }
155         else
156         {
157                 CFile *pFile = pDataObject->GetFileData(CWDClipboardData::Instance()->GetClipboardFormat(format));
158                 if (pFile)
159                 {
160                         CArchive ar(pFile,CArchive::load);
161                         pObj->Serialize(ar);
162                         ar.Close();
163                         delete pFile;
164                 }
165         }
166         return true;
167 }
168
169 ///////////////////////////////////////////
170 //
171 //      Clipboard objects
172 //
173 ///////////////////////////////////////////
174 IMPLEMENT_SERIAL(CCF_App, CObject, 0 );
175 IMPLEMENT_SERIAL(CCF_WebSites,CObject,0);
176 IMPLEMENT_SERIAL(CCF_String, CObject, 0 );
177 IMPLEMENT_SERIAL(CCF_WebSite, CObject, 0 );
178 IMPLEMENT_SERIAL(CCF_FolderType, CObject, 0 );
179 IMPLEMENT_SERIAL(CCF_DBFolderList,CObject,0);
180 IMPLEMENT_SERIAL(CCF_RightMenu, CObject, 0 );
181 IMPLEMENT_SERIAL(CCF_FileGroupDescriptor,CObject,0);
182 IMPLEMENT_SERIAL(CCF_ShellIDList,CObject,0);
183 IMPLEMENT_SERIAL(CCF_HDROP,CObject,0);
184 ///////////////////////////////////////////
185 bool CCF_RightMenu::IsRightDrag()
186 {
187         return m_bRightDrag;
188 }
189
190 void CCF_RightMenu::SetRightDrag(bool bRightDrag)
191 {
192         m_bRightDrag = bRightDrag;
193 }
194
195 void CCF_RightMenu::Serialize(CArchive &ar)
196 {
197         if (ar.IsLoading())
198         {
199                 int nRightDrag;
200                 ar >> nRightDrag;
201                 m_bRightDrag = nRightDrag == 1;
202         }
203         else
204         {
205                 ar << m_bRightDrag;
206         }
207 }
208
209 CCF_FileGroupDescriptor::CCF_FileGroupDescriptor() 
210 {
211         m_pFileDescrs = NULL;
212         m_nItems = 0;
213 }
214
215 CCF_FileGroupDescriptor::~CCF_FileGroupDescriptor()
216 {
217         delete []m_pFileDescrs;
218 }
219
220 LPFILEDESCRIPTOR CCF_FileGroupDescriptor::GetFileDescriptor(UINT nItem)
221 {
222         if (m_pFileDescrs == NULL)
223                 return NULL;
224         if (nItem >= m_nItems)
225         {
226                 ASSERT(FALSE);
227                 return NULL;
228         }
229         return &m_pFileDescrs[nItem];
230 }
231
232 void CCF_FileGroupDescriptor::SetTitle(const CString &sTitle)
233 {
234         m_sTitle = sTitle;
235 }
236
237 CString CCF_FileGroupDescriptor::GetFileName(UINT nItem)
238 {
239         if (nItem >= m_nItems || m_pFileDescrs == NULL)
240         {
241                 ASSERT(FALSE);
242                 return CString();
243         }
244         return m_pFileDescrs[nItem].cFileName;
245 }
246
247 CString CCF_FileGroupDescriptor::GetTitle(UINT nItem)
248 {
249         if (nItem >= m_nItems || m_pFileDescrs == NULL)
250         {
251                 ASSERT(FALSE);
252                 return CString();
253         }
254         CString strLink(m_pFileDescrs[nItem].cFileName);
255         int nPos = strLink.Find(_T(".URL"));
256         if (nPos < 0)
257                 nPos = strLink.Find(_T(".url"));
258         if (nPos > 0)
259         {
260                 return strLink.Left(nPos);
261         }
262         return strLink;
263 }
264
265 void CCF_FileGroupDescriptor::Serialize(CArchive &ar)
266 {
267         if (ar.IsLoading())
268         {
269                 ar.Read(&m_nItems,sizeof(UINT));
270                 if (m_nItems)
271                 {
272                         m_pFileDescrs = new FILEDESCRIPTOR[m_nItems];
273                         ar.Read(m_pFileDescrs,sizeof(FILEDESCRIPTOR)*m_nItems);
274                         for(UINT i=0;i < m_nItems;i++)
275                                 TRACE3("(%u) - cFileName %s, Size=%u\n",i,m_pFileDescrs[i].cFileName,m_pFileDescrs[i].nFileSizeLow);
276                 }
277         }
278         else
279         {
280                 UINT cItems=1;
281                 ar.Write(&cItems,sizeof(UINT));
282                 FILEDESCRIPTOR FileDesc;
283                 ZeroMemory(&FileDesc,sizeof(FILEDESCRIPTOR));
284                 FileDesc.dwFlags = (FD_LINKUI | FD_FILESIZE);
285                 if (!m_sTitle.IsEmpty())
286                 {
287                         lstrcpy(FileDesc.cFileName,m_sTitle);
288                         lstrcat(FileDesc.cFileName,_T(".url"));
289                         FileDesc.nFileSizeLow = lstrlen(FileDesc.cFileName)+24;
290                         ar.Write(&FileDesc,sizeof(FILEDESCRIPTOR));
291                 }
292         }
293 }
294
295 ////////////////////////////////////////////////
296 // CCF_HDROP
297 ////////////////////////////////////////////////
298 CCF_HDROP::CCF_HDROP() 
299 {
300         m_nFiles = 0;
301         m_fNC = FALSE;
302 }
303
304 CCF_HDROP::~CCF_HDROP()
305 {
306 }
307
308 CString CCF_HDROP::GetFileName(UINT nItem)
309 {
310         if (m_sFileNames.GetSize() > 0)
311                 return m_sFileNames[nItem];
312         return _T("");
313 }
314
315 void CCF_HDROP::AddDropPoint(CPoint &pt,BOOL fNC)
316 {
317         m_pt = pt;
318         m_fNC = fNC;
319 }
320
321 void CCF_HDROP::AddFileName(LPCTSTR pszFileName)
322 {
323         m_sFileNames.SetAtGrow(m_nFiles++,pszFileName);
324 }
325
326 void CCF_HDROP::Serialize(CArchive &ar)
327 {
328         if (ar.IsLoading())
329         {
330                 // handled in GetData
331         }
332         else
333         {
334                 DROPFILES dropfiles;
335                 dropfiles.pFiles = sizeof(dropfiles);
336                 dropfiles.fNC = m_fNC;
337                 dropfiles.pt = m_pt;
338 #ifdef _UNICODE
339                 dropfiles.fWide = TRUE;
340 #else
341                 dropfiles.fWide = FALSE;
342 #endif
343                 ar.Write(&dropfiles,sizeof(DROPFILES));
344                 LPCTSTR pszFileName=NULL;
345                 for(int i=0; i < m_nFiles;i++)
346                 {
347                         pszFileName=m_sFileNames[i];
348                         ar.Write(pszFileName,lstrlen(pszFileName)+sizeof(TCHAR));
349                 }
350                 TCHAR rchar=0;
351                 ar.Write(&rchar,sizeof(TCHAR));
352         }
353 }
354
355 ////////////////////////////////////////////////
356 // CCF_ShellIDList
357 ////////////////////////////////////////////////
358 CCF_ShellIDList::CCF_ShellIDList() 
359 {
360 }
361
362 CCF_ShellIDList::~CCF_ShellIDList()
363 {
364 }
365
366 LPCITEMIDLIST CCF_ShellIDList::operator[](UINT nIndex) const
367 {
368         return GetPidl(nIndex);
369 }
370
371 LPCITEMIDLIST CCF_ShellIDList::GetPidl(UINT nIndex) const
372 {
373         if (nIndex > (UINT)m_pidls.GetSize()) 
374         { 
375                 return NULL; 
376         } 
377         return(m_pidls[nIndex]); 
378 }
379
380 UINT CCF_ShellIDList::GetCount() const
381 {
382         return m_pidls.GetSize();  
383 }
384
385 void CCF_ShellIDList::AddPidl(LPCITEMIDLIST pidl)
386 {
387         m_pidls.Add(pidl);
388 }
389
390 void CCF_ShellIDList::Serialize(CArchive &ar)
391 {
392         if (ar.IsLoading())
393         {
394                 // read the header
395                 CIDA cida;
396                 ar.Read(&cida,sizeof(CIDA));
397                 LPCITEMIDLIST pidl=NULL;
398                 UINT nOffset;
399                 // read the ITEMIDLIST structures
400                 for(UINT i=0;i < cida.cidl+1;i++)
401                 {
402                         nOffset = cida.aoffset[i];
403                         ar.GetFile()->Seek(CFile::begin,nOffset*sizeof(UINT));
404                         ar.Read((void*)pidl,sizeof(ITEMIDLIST));
405                         m_pidls.Add(pidl);
406                 }
407         }
408         else
409         {
410                 CShellPidl ShellPidl;
411                 CIDA cida;
412                 cida.cidl = m_pidls.GetSize();
413                 ASSERT(cida.cidl > 1);
414                 if (cida.cidl <= 1)
415                         return;
416                 UINT pidls=cida.cidl-1;
417                 ar.Write(&pidls,sizeof(pidls));
418                 const UINT nOffset=sizeof(UINT);
419                 UINT nElemOffset;
420                 UINT nPidlSize=0;
421                 for(UINT i1=0;i1 < cida.cidl;i1++)
422                 {
423                         nElemOffset = sizeof(cida.cidl)+(cida.cidl*sizeof(nElemOffset))+nOffset+nPidlSize;
424                         ar.Write(&nElemOffset,sizeof(nElemOffset));
425                         nPidlSize += ShellPidl.GetSize(m_pidls[i1]);
426                 }
427                 BYTE nZero=0;
428                 for(int i=0;i < nOffset;i++)
429                         ar.Write(&nZero,sizeof(nZero));
430                 TRACE1("Writing %u pidls\n",cida.cidl);
431                 LPSHELLFOLDER pFolder=ShellPidl.GetFolder((LPITEMIDLIST)m_pidls[0]);
432                 for(UINT i2=0;i2 < cida.cidl;i2++)
433                 {
434 #ifdef _DEBUG
435                         CString sPath;
436                         ShellPidl.SHPidlToPathEx((LPITEMIDLIST)m_pidls[i2],sPath,pFolder);
437                         TRACE3("Writing pidl %s (%u) size(%u)\n",sPath,i2,ShellPidl.GetSize(m_pidls[i2]));
438 #endif  
439                         ar.Write(m_pidls[i2],ShellPidl.GetSize(m_pidls[i2]));
440                 }
441                 if (pFolder)
442                         pFolder->Release();
443         }
444 }
445
446 ///////////////////////////////////////////////////////////////////
447 // Private clipboard formats for drag and drop
448 ///////////////////////////////////////////////////////////////////
449 const CCF_WebSite &CCF_WebSite::operator=(const CCF_WebSite &rThat)
450 {
451         if (this != &rThat)
452         {
453                 m_strURL = rThat.m_strURL;
454                 m_strTitle = rThat.m_strTitle;
455         }
456         return *this;
457 }
458
459 CCF_WebSite::CCF_WebSite(const CCF_WebSite &WebSite)
460 {
461         *this = WebSite;
462 }
463
464 ////////////////////////////////////////////
465
466 void CCF_App::Serialize(CArchive &ar)
467 {
468         if (ar.IsLoading())
469         {
470                 long hWnd;
471                 ar >> hWnd;
472                 m_hWnd = (HWND)hWnd;
473         }
474         else
475         {
476                 ar << (long)m_hWnd;
477         }
478 }
479 /////////////////////////////////////////
480
481 void CCF_WebSites::Serialize(CArchive &ar)
482 {
483         m_App.Serialize(ar);
484         m_listWebSites.Serialize(ar);
485 }
486
487 /////////////////////////////////////////
488
489 CCF_String::CCF_String(LPCTSTR pszText) : m_sText(pszText) 
490 {
491 }
492
493 CCF_String::~CCF_String()
494 {
495 }
496
497 LPCTSTR CCF_String::GetString()
498 {
499         return m_sText;
500 }
501
502 void CCF_String::SetString(LPCTSTR pszText)
503 {
504         m_sText = pszText;
505 }
506
507 void CCF_String::Serialize(CArchive &ar)
508 {
509         if (ar.IsLoading())
510         {
511                 TCHAR szText[MAX_PATH+1];
512                 m_sText.Empty();
513                 while (1)
514                 {
515                         ZeroMemory(szText,sizeof(szText));
516                         ar.Read(szText,MAX_PATH);
517                         m_sText += szText;
518                         if (lstrlen(szText) < MAX_PATH)
519                                 break;
520                 }
521         }
522         else
523         {
524                 ar.Write((LPCTSTR)m_sText, m_sText.GetLength()*sizeof(TCHAR));
525                 int null=0;
526                 ar.Write(&null,sizeof(null));
527         }
528 }
529
530 //
531 // Private clipboard formats for drag and drop
532 //
533 CCF_WebSite::CCF_WebSite(LPCTSTR pszURL,LPCTSTR pszTitle) : 
534         m_strURL(pszURL),
535                 m_strTitle(pszTitle)
536 {
537 }
538
539 CCF_WebSite::~CCF_WebSite()
540 {
541 }
542
543 void CCF_WebSite::Serialize(CArchive &ar)
544 {
545         if (ar.IsLoading())
546         {
547                 ar >> m_strURL;
548                 ar >> m_strTitle;
549         }
550         else
551         {
552                 ar << m_strURL;
553                 ar << m_strTitle;
554         }
555 }
556
557 //
558 //////////////////////////////////////////////////////
559
560 CCF_FolderType::CCF_FolderType(LPCTSTR pszParentCategory,long nCategory,LPCTSTR pszCategory) :
561                 m_strParentCategory(pszParentCategory),
562                 m_nCategory(nCategory),
563                 m_strCategory(pszCategory)
564 {
565 }
566
567 CCF_FolderType::~CCF_FolderType()
568 {
569 }
570
571 const CCF_FolderType &CCF_FolderType::operator=(const CCF_FolderType &rThat)
572 {
573         if (this != &rThat)
574         {
575                 m_nCategory = rThat.m_nCategory;
576                 m_strCategory = rThat.m_strCategory;
577                 m_strParentCategory = rThat.m_strParentCategory;
578         }
579         return *this;
580 }
581
582 CCF_FolderType::CCF_FolderType(const CCF_FolderType &WebSiteCategory)
583 {
584         *this = WebSiteCategory;
585 }
586
587 void CCF_FolderType::Serialize(CArchive &ar)
588 {
589         if (ar.IsLoading())
590         {
591                 ar >> m_nCategory;
592                 ar >> m_strCategory;
593                 ar >> m_strParentCategory;
594         }
595         else
596         {
597                 ar << m_nCategory;
598                 ar << m_strCategory;
599                 ar << m_strParentCategory;
600         }
601 }
602
603 /////////////////////////////////////////////////
604
605 void CCF_DBFolderList::Serialize(CArchive &ar)
606 {
607         m_App.Serialize(ar);
608         if (ar.IsLoading())
609         {
610                 ar >> m_strDatabase;
611         }
612         else
613         {
614                 ar << m_strDatabase;
615         }
616         CList<CCF_FolderType,CCF_FolderType&>::Serialize(ar);
617 }
618
619 template <> void AFXAPI SerializeElements <CCF_FolderType>(CArchive& ar, CCF_FolderType *pWebSite, int nCount )
620 {
621     for ( int i = 0; i < nCount; i++, pWebSite++ )
622     {
623                 pWebSite->Serialize(ar);
624         }
625 }
626
627 template<> void AFXAPI DestructElements<CCF_FolderType> (CCF_FolderType *pElements, int nCount)
628 {
629         for ( int n = 0; n < nCount; n++, pElements++ )
630         {
631                 pElements->CCF_FolderType::~CCF_FolderType();
632         }
633 }
634
635 template<> void AFXAPI ConstructElements<CCF_FolderType> (CCF_FolderType *pElements, int nCount)
636 {
637         for ( int n = 0; n < nCount; n++, pElements++ )
638         {
639                 pElements->CCF_FolderType::CCF_FolderType();
640         }
641 }
642
643 ///////////////////////////////////////////////////     
644 template <> void AFXAPI SerializeElements <CCF_WebSite>(CArchive& ar, CCF_WebSite *pWebSite, int nCount )
645 {
646     for ( int i = 0; i < nCount; i++, pWebSite++ )
647     {
648                 pWebSite->Serialize(ar);
649         }
650 }
651
652 template<> void AFXAPI DestructElements<CCF_WebSite> (CCF_WebSite *pElements, int nCount)
653 {
654         for ( int n = 0; n < nCount; n++, pElements++ )
655         {
656                 pElements->CCF_WebSite::~CCF_WebSite();
657         }
658 }
659
660 template<> void AFXAPI ConstructElements<CCF_WebSite> (CCF_WebSite *pElements, int nCount)
661 {
662         for ( int n = 0; n < nCount; n++, pElements++ )
663         {
664                 pElements->CCF_WebSite::CCF_WebSite();
665         }
666 }
667