1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <config.hxx>
21 #include <global.hxx>
22 
23 #include <propsheets.hxx>
24 #include <utilities.hxx>
25 #include <resource.h>
26 #include "listviewbuilder.hxx"
27 
28 #include <shellapi.h>
29 
30 #include <sal/macros.h>
31 
32 #include <memory>
33 #include <string>
34 #include <vector>
35 #include <utility>
36 #include <strsafe.h>
37 
38 
39 /*---------------------------------------------
40     INFO - INFO - INFO - INFO - INFO - INFO
41 
42     See MSDN "Using Windows XP Visual Styles"
43     for hints how to enable the new common
44     control library for our property sheet.
45 
46     INFO - INFO - INFO - INFO - INFO - INFO
47 ----------------------------------------------*/
48 
49 
CPropertySheet(LONG RefCnt)50 CPropertySheet::CPropertySheet(LONG RefCnt) :
51     m_RefCnt(RefCnt)
52 {
53     OutputDebugStringFormatW(L"CPropertySheet::CTor [%d], [%ld]", m_RefCnt, g_DllRefCnt );
54     InterlockedIncrement(&g_DllRefCnt);
55 }
56 
57 
~CPropertySheet()58 CPropertySheet::~CPropertySheet()
59 {
60     OutputDebugStringFormatW(L"CPropertySheet::DTor [%d], [%ld]", m_RefCnt, g_DllRefCnt );
61     InterlockedDecrement(&g_DllRefCnt);
62 }
63 
64 
65 // IUnknown methods
66 
67 
QueryInterface(REFIID riid,void __RPC_FAR * __RPC_FAR * ppvObject)68 HRESULT STDMETHODCALLTYPE CPropertySheet::QueryInterface(
69     REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject)
70 {
71     *ppvObject = nullptr;
72 
73     IUnknown* pUnk = nullptr;
74     if (IID_IUnknown == riid || IID_IShellExtInit == riid)
75     {
76         pUnk = static_cast<IShellExtInit*>(this);
77         pUnk->AddRef();
78         *ppvObject = pUnk;
79         return S_OK;
80     }
81     else if (IID_IShellPropSheetExt == riid)
82     {
83         pUnk = static_cast<IShellPropSheetExt*>(this);
84         pUnk->AddRef();
85         *ppvObject = pUnk;
86         return S_OK;
87     }
88 
89     return E_NOINTERFACE;
90 }
91 
92 
AddRef()93 ULONG STDMETHODCALLTYPE CPropertySheet::AddRef()
94 {
95     OutputDebugStringFormatW(L"CPropertySheet::AddRef [%d]", m_RefCnt );
96     return InterlockedIncrement(&m_RefCnt);
97 }
98 
99 
Release()100 ULONG STDMETHODCALLTYPE CPropertySheet::Release()
101 {
102     OutputDebugStringFormatW(L"CPropertySheet::Release [%d]", m_RefCnt );
103     LONG refcnt = InterlockedDecrement(&m_RefCnt);
104 
105     if (0 == refcnt)
106         delete this;
107 
108     return refcnt;
109 }
110 
111 
112 // IShellExtInit
113 
114 
Initialize(LPCITEMIDLIST,IDataObject * lpdobj,HKEY)115 HRESULT STDMETHODCALLTYPE CPropertySheet::Initialize(
116     LPCITEMIDLIST /*pidlFolder*/, IDataObject * lpdobj, HKEY /*hkeyProgID*/)
117 {
118     InitCommonControls();
119 
120     STGMEDIUM medium;
121     FORMATETC fe = {CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
122 
123     HRESULT hr = lpdobj->GetData(&fe, &medium);
124 
125     // save the file name
126     if (SUCCEEDED(hr) &&
127         (1 == DragQueryFileW(
128             static_cast<HDROP>(medium.hGlobal),
129             0xFFFFFFFF,
130             nullptr,
131             0)))
132     {
133         UINT size = DragQueryFileW( static_cast<HDROP>(medium.hGlobal), 0, nullptr, 0 );
134         if ( size != 0 )
135         {
136             auto buffer = std::make_unique<WCHAR[]>( size + 1 );
137             UINT result_size = DragQueryFileW( static_cast<HDROP>(medium.hGlobal),
138                                                0, buffer.get(), size + 1 );
139             if ( result_size != 0 )
140             {
141                 std::wstring fname = getShortPathName( buffer.get() );
142                 ZeroMemory( m_szFileName, sizeof( m_szFileName ) );
143                 wcsncpy( m_szFileName, fname.c_str(), ( SAL_N_ELEMENTS( m_szFileName ) - 1 ) );
144                 hr = S_OK;
145             }
146             else
147                 hr = E_INVALIDARG;
148         }
149         else
150             hr = E_INVALIDARG;
151     }
152     else
153         hr = E_INVALIDARG;
154 
155     ReleaseStgMedium(&medium);
156 
157     return hr;
158 }
159 
160 
161 // IShellPropSheetExt
162 
163 
AddPages(LPFNSVADDPROPSHEETPAGE lpfnAddPage,LPARAM lParam)164 HRESULT STDMETHODCALLTYPE CPropertySheet::AddPages(LPFNSVADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
165 {
166     std::wstring proppage_header;
167 
168     PROPSHEETPAGEW psp;
169     ZeroMemory(&psp, sizeof(psp));
170 
171     // add the summary property page
172     psp.dwSize      = sizeof(psp);
173     psp.dwFlags     = PSP_DEFAULT | PSP_USETITLE | PSP_USECALLBACK;
174     psp.hInstance   = GetModuleHandleW(MODULE_NAME);
175     psp.lParam      = reinterpret_cast<LPARAM>(this);
176     psp.pfnCallback = reinterpret_cast<LPFNPSPCALLBACKW>(CPropertySheet::PropPageSummaryCallback);
177 
178     HPROPSHEETPAGE hPage = nullptr;
179 
180     // add the statistics property page
181     proppage_header = GetResString(IDS_PROPPAGE_STATISTICS_TITLE);
182 
183     psp.pszTemplate = MAKEINTRESOURCEW(IDD_PROPPAGE_STATISTICS);
184     psp.pszTitle    = proppage_header.c_str();
185     psp.pfnDlgProc  = reinterpret_cast<DLGPROC>(CPropertySheet::PropPageStatisticsProc);
186 
187     hPage = CreatePropertySheetPageW(&psp);
188 
189     if (hPage)
190     {
191         if (lpfnAddPage(hPage, lParam))
192             AddRef();
193         else
194             DestroyPropertySheetPage(hPage);
195     }
196 
197     // always return success else no property sheet will be displayed at all
198     return NOERROR;
199 }
200 
201 
ReplacePage(EXPPS,LPFNSVADDPROPSHEETPAGE,LPARAM)202 HRESULT STDMETHODCALLTYPE CPropertySheet::ReplacePage(
203     EXPPS /*uPageID*/, LPFNSVADDPROPSHEETPAGE /*lpfnReplaceWith*/, LPARAM /*lParam*/)
204 {
205     return E_NOTIMPL;
206 }
207 
208 
PropPageSummaryCallback(HWND,UINT uMsg,LPPROPSHEETPAGE ppsp)209 UINT CALLBACK CPropertySheet::PropPageSummaryCallback(
210     HWND /*hwnd*/, UINT uMsg, LPPROPSHEETPAGE ppsp)
211 {
212     CPropertySheet* pImpl =
213         reinterpret_cast<CPropertySheet*>(ppsp->lParam);
214 
215     // release this instance, acquired in the AddPages method
216     if (PSPCB_RELEASE == uMsg)
217     {
218         pImpl->Release();
219     }
220 
221     return TRUE;
222 }
223 
224 
PropPageSummaryProc(HWND hwnd,UINT uiMsg,WPARAM,LPARAM lParam)225 bool CALLBACK CPropertySheet::PropPageSummaryProc(HWND hwnd, UINT uiMsg, WPARAM /*wParam*/, LPARAM lParam)
226 {
227     switch (uiMsg)
228     {
229     case WM_INITDIALOG:
230         {
231             LPPROPSHEETPAGE psp = reinterpret_cast<LPPROPSHEETPAGE>(lParam);
232             CPropertySheet* pImpl = reinterpret_cast<CPropertySheet*>(psp->lParam);
233             pImpl->InitPropPageSummary(hwnd, psp);
234             return true;
235         }
236     }
237 
238     return false;
239 }
240 
241 
PropPageStatisticsProc(HWND hwnd,UINT uiMsg,WPARAM,LPARAM lParam)242 BOOL CALLBACK CPropertySheet::PropPageStatisticsProc(HWND hwnd, UINT uiMsg, WPARAM /*wParam*/, LPARAM lParam)
243 {
244     switch (uiMsg)
245     {
246     case WM_INITDIALOG:
247         {
248             LPPROPSHEETPAGE psp = reinterpret_cast<LPPROPSHEETPAGE>(lParam);
249             CPropertySheet* pImpl = reinterpret_cast<CPropertySheet*>(psp->lParam);
250             pImpl->InitPropPageStatistics(hwnd, psp);
251             return TRUE;
252         }
253     }
254 
255     return FALSE;
256 }
257 
InitPropPageSummary(HWND hwnd,LPPROPSHEETPAGE)258 void CPropertySheet::InitPropPageSummary(HWND hwnd, LPPROPSHEETPAGE /*lppsp*/)
259 {
260     try
261     {
262         CMetaInfoReader metaInfo(m_szFileName);
263 
264         SetWindowTextW(GetDlgItem(hwnd,IDC_TITLE),    metaInfo.getTagData( META_INFO_TITLE ).c_str() );
265         SetWindowTextW(GetDlgItem(hwnd,IDC_AUTHOR),   metaInfo.getTagData( META_INFO_AUTHOR ).c_str() );
266         SetWindowTextW(GetDlgItem(hwnd,IDC_SUBJECT),  metaInfo.getTagData( META_INFO_SUBJECT ).c_str() );
267         SetWindowTextW(GetDlgItem(hwnd,IDC_KEYWORDS), metaInfo.getTagData( META_INFO_KEYWORDS ).c_str() );
268 
269         // comments read from meta.xml use "\n" for return, but this will not displayable in Edit control, add
270         // "\r" before "\n" to form "\r\n" in order to display return in Edit control.
271         std::wstring tempStr = metaInfo.getTagData( META_INFO_DESCRIPTION );
272         std::wstring::size_type itor = tempStr.find ( L"\n" , 0 );
273         while (itor != std::wstring::npos)
274         {
275             tempStr.insert(itor, L"\r");
276             itor = tempStr.find(L"\n", itor + 2);
277         }
278         SetWindowTextW(GetDlgItem(hwnd,IDC_COMMENTS), tempStr.c_str());
279     }
280     catch (const std::exception&)
281     {
282     }
283 }
284 
285 
InitPropPageStatistics(HWND hwnd,LPPROPSHEETPAGE)286 void CPropertySheet::InitPropPageStatistics(HWND hwnd, LPPROPSHEETPAGE /*lppsp*/)
287 {
288     try
289     {
290         CMetaInfoReader metaInfo(m_szFileName);
291 
292         document_statistic_reader_ptr doc_stat_reader = create_document_statistic_reader(m_szFileName, &metaInfo);
293 
294         statistic_group_list_t sgl;
295         doc_stat_reader->read(&sgl);
296 
297         list_view_builder_ptr lv_builder = create_list_view_builder(
298             GetDlgItem(hwnd, IDC_STATISTICSLIST),
299             GetResString(IDS_PROPERTY),
300             GetResString(IDS_PROPERTY_VALUE));
301 
302         lv_builder->build(sgl);
303     }
304     catch (const std::exception&)
305     {
306     }
307 }
308 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
309