1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sd.hxx"
26 
27 #include "CurrentMasterPagesSelector.hxx"
28 #include "PreviewValueSet.hxx"
29 #include "ViewShellBase.hxx"
30 #include "DrawViewShell.hxx"
31 #include "drawdoc.hxx"
32 #include "sdpage.hxx"
33 #include "MasterPageContainer.hxx"
34 #include "MasterPageDescriptor.hxx"
35 #include "EventMultiplexer.hxx"
36 #include "app.hrc"
37 #include "DrawDocShell.hxx"
38 #include "DrawViewShell.hxx"
39 #include "res_bmp.hrc"
40 #include "sdresid.hxx"
41 
42 #include <vcl/image.hxx>
43 #include <svx/svdmodel.hxx>
44 #include <sfx2/request.hxx>
45 
46 #include <set>
47 
48 
49 using namespace ::com::sun::star;
50 
51 namespace sd { namespace toolpanel { namespace controls {
52 
53 
54 CurrentMasterPagesSelector::CurrentMasterPagesSelector (
55     TreeNode* pParent,
56     SdDrawDocument& rDocument,
57     ViewShellBase& rBase,
58     const ::boost::shared_ptr<MasterPageContainer>& rpContainer)
59     : MasterPagesSelector (pParent, rDocument, rBase, rpContainer)
60 {
61 	SetName(String(RTL_CONSTASCII_USTRINGPARAM("CurrentMasterPagesSelector")));
62 
63     // For this master page selector only we change the default action for
64     // left clicks.
65     mnDefaultClickAction = SID_TP_APPLY_TO_SELECTED_SLIDES;
66 
67     Link aLink (LINK(this,CurrentMasterPagesSelector,EventMultiplexerListener));
68     rBase.GetEventMultiplexer()->AddEventListener(aLink,
69         sd::tools::EventMultiplexerEvent::EID_CURRENT_PAGE
70         | sd::tools::EventMultiplexerEvent::EID_EDIT_MODE_NORMAL
71         | sd::tools::EventMultiplexerEvent::EID_EDIT_MODE_MASTER
72         | sd::tools::EventMultiplexerEvent::EID_PAGE_ORDER
73         | sd::tools::EventMultiplexerEvent::EID_SHAPE_CHANGED
74         | sd::tools::EventMultiplexerEvent::EID_SHAPE_INSERTED
75         | sd::tools::EventMultiplexerEvent::EID_SHAPE_REMOVED);
76 }
77 
78 
79 
80 
81 CurrentMasterPagesSelector::~CurrentMasterPagesSelector (void)
82 {
83     if (mrDocument.GetDocSh() != NULL)
84     {
85         EndListening(*mrDocument.GetDocSh());
86     }
87     else
88     {
89         OSL_ASSERT(mrDocument.GetDocSh() != NULL);
90     }
91 
92     Link aLink (LINK(this,CurrentMasterPagesSelector,EventMultiplexerListener));
93     mrBase.GetEventMultiplexer()->RemoveEventListener(aLink);
94 }
95 
96 
97 
98 
99 void CurrentMasterPagesSelector::LateInit (void)
100 {
101     MasterPagesSelector::LateInit();
102     MasterPagesSelector::Fill();
103     if (mrDocument.GetDocSh() != NULL)
104     {
105         StartListening(*mrDocument.GetDocSh());
106     }
107     else
108     {
109         OSL_ASSERT(mrDocument.GetDocSh() != NULL);
110     }
111 }
112 
113 
114 
115 
116 void CurrentMasterPagesSelector::Fill (ItemList& rItemList)
117 {
118 	sal_uInt16 nPageCount = mrDocument.GetMasterSdPageCount(PK_STANDARD);
119     SdPage* pMasterPage;
120     // Remember the names of the master pages that have been inserted to
121     // avoid double insertion.
122     ::std::set<String> aMasterPageNames;
123     for (sal_uInt16 nIndex=0; nIndex<nPageCount; nIndex++)
124     {
125         pMasterPage = mrDocument.GetMasterSdPage (nIndex, PK_STANDARD);
126         if (pMasterPage == NULL)
127             continue;
128 
129         // Use the name of the master page to avoid duplicate entries.
130         String sName (pMasterPage->GetName());
131         if (aMasterPageNames.find(sName)!=aMasterPageNames.end())
132             continue;
133         aMasterPageNames.insert (sName);
134 
135         // Look up the master page in the container and, when it is not yet
136         // in it, insert it.
137         MasterPageContainer::Token aToken = mpContainer->GetTokenForPageObject(pMasterPage);
138         if (aToken == MasterPageContainer::NIL_TOKEN)
139         {
140             SharedMasterPageDescriptor pDescriptor (new MasterPageDescriptor(
141                 MasterPageContainer::MASTERPAGE,
142                 nIndex,
143                 String(),
144                 pMasterPage->GetName(),
145                 String(),
146                 pMasterPage->IsPrecious(),
147                 ::boost::shared_ptr<PageObjectProvider>(new ExistingPageProvider(pMasterPage)),
148                 ::boost::shared_ptr<PreviewProvider>(new PagePreviewProvider())));
149             aToken = mpContainer->PutMasterPage(pDescriptor);
150         }
151 
152         rItemList.push_back(aToken);
153     }
154 }
155 
156 
157 
158 
159 ResId CurrentMasterPagesSelector::GetContextMenuResId (void) const
160 {
161     return SdResId(RID_TASKPANE_CURRENT_MASTERPAGESSELECTOR_POPUP);
162 }
163 
164 
165 
166 
167 void CurrentMasterPagesSelector::UpdateSelection (void)
168 {
169     // Iterate over all pages and for the selected ones put the name of
170     // their master page into a set.
171 	sal_uInt16 nPageCount = mrDocument.GetSdPageCount(PK_STANDARD);
172     SdPage* pPage;
173     ::std::set<String> aNames;
174     sal_uInt16 nIndex;
175     bool bLoop (true);
176     for (nIndex=0; nIndex<nPageCount && bLoop; nIndex++)
177     {
178         pPage = mrDocument.GetSdPage (nIndex, PK_STANDARD);
179         if (pPage != NULL && pPage->IsSelected())
180         {
181             if ( ! pPage->TRG_HasMasterPage())
182             {
183                 // One of the pages has no master page.  This is an
184                 // indicator for that this method is called in the middle of
185                 // a document change and that the model is not in a valid
186                 // state.  Therefore we stop update the selection and wait
187                 // for another call to UpdateSelection when the model is
188                 // valid again.
189                 bLoop = false;
190             }
191             else
192             {
193                 SdrPage& rMasterPage (pPage->TRG_GetMasterPage());
194                 SdPage* pMasterPage = static_cast<SdPage*>(&rMasterPage);
195                 if (pMasterPage != NULL)
196                     aNames.insert (pMasterPage->GetName());
197             }
198         }
199     }
200 
201     // Find the items for the master pages in the set.
202     sal_uInt16 nItemCount (mpPageSet->GetItemCount());
203     for (nIndex=1; nIndex<=nItemCount && bLoop; nIndex++)
204     {
205         String sName (mpPageSet->GetItemText (nIndex));
206         if (aNames.find(sName) != aNames.end())
207         {
208             mpPageSet->SelectItem (nIndex);
209         }
210     }
211 }
212 
213 
214 
215 
216 void CurrentMasterPagesSelector::Execute (SfxRequest& rRequest)
217 {
218 	switch (rRequest.GetSlot())
219     {
220         case SID_DELETE_MASTER_PAGE:
221         {
222             // Check once again that the master page can safely be deleted,
223             // i.e. is not used.
224             SdPage* pMasterPage = GetSelectedMasterPage();
225             if (pMasterPage != NULL
226                 && mrDocument.GetMasterPageUserCount(pMasterPage) == 0)
227             {
228                 // Removing the precious flag so that the following call to
229                 // RemoveUnnessesaryMasterPages() will remove this master page.
230                 pMasterPage->SetPrecious(false);
231                 mrDocument.RemoveUnnecessaryMasterPages(pMasterPage, sal_False, sal_True);
232             }
233         }
234         break;
235 
236         default:
237             MasterPagesSelector::Execute(rRequest);
238             break;
239     }
240 }
241 
242 
243 
244 
245 void CurrentMasterPagesSelector::GetState (SfxItemSet& rItemSet)
246 {
247     // Disable the SID_DELTE_MASTER slot when there is only one master page.
248     if (rItemSet.GetItemState(SID_DELETE_MASTER_PAGE) == SFX_ITEM_AVAILABLE
249         && mrDocument.GetMasterPageUserCount(GetSelectedMasterPage()) > 0)
250     {
251         rItemSet.DisableItem(SID_DELETE_MASTER_PAGE);
252     }
253 
254     ::boost::shared_ptr<DrawViewShell> pDrawViewShell (
255         ::boost::dynamic_pointer_cast<DrawViewShell>(mrBase.GetMainViewShell()));
256 	if (rItemSet.GetItemState(SID_TP_EDIT_MASTER) == SFX_ITEM_AVAILABLE
257         && pDrawViewShell
258         && pDrawViewShell->GetEditMode() == EM_MASTERPAGE)
259     {
260         rItemSet.DisableItem (SID_TP_EDIT_MASTER);
261     }
262 
263     MasterPagesSelector::GetState(rItemSet);
264 }
265 
266 
267 
268 
269 
270 
271 IMPL_LINK(CurrentMasterPagesSelector,EventMultiplexerListener,
272     sd::tools::EventMultiplexerEvent*,pEvent)
273 {
274     if (pEvent != NULL)
275     {
276         switch (pEvent->meEventId)
277         {
278             case sd::tools::EventMultiplexerEvent::EID_CURRENT_PAGE:
279             case sd::tools::EventMultiplexerEvent::EID_EDIT_MODE_NORMAL:
280             case sd::tools::EventMultiplexerEvent::EID_EDIT_MODE_MASTER:
281             case sd::tools::EventMultiplexerEvent::EID_SLIDE_SORTER_SELECTION:
282                 UpdateSelection();
283                 break;
284 
285             case sd::tools::EventMultiplexerEvent::EID_PAGE_ORDER:
286 				// This is tricky.  If a master page is removed, moved, or
287 				// added we have to wait until both the notes master page
288 				// and the standard master page have been removed, moved,
289 				// or added.  We do this by looking at the number of master
290 				// pages which has to be odd in the consistent state (the
291 				// handout master page is always present).  If the number is
292 				// even we ignore the hint.
293                 if (mrBase.GetDocument()->GetMasterPageCount()%2 == 1)
294                     MasterPagesSelector::Fill();
295                 break;
296 
297             case sd::tools::EventMultiplexerEvent::EID_SHAPE_CHANGED:
298             case sd::tools::EventMultiplexerEvent::EID_SHAPE_INSERTED:
299             case sd::tools::EventMultiplexerEvent::EID_SHAPE_REMOVED:
300                 InvalidatePreview((const SdPage*)pEvent->mpUserData);
301                 break;
302         }
303     }
304 
305     return 0;
306 }
307 
308 
309 
310 
311 void CurrentMasterPagesSelector::Notify (SfxBroadcaster&, const SfxHint& rHint)
312 {
313     const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint);
314     if (pSimpleHint != NULL)
315     {
316         if (pSimpleHint->GetId() == SFX_HINT_DOCCHANGED)
317         {
318             // Is the edit view visible in the center pane?
319             ::boost::shared_ptr<DrawViewShell> pDrawViewShell (
320                 ::boost::dynamic_pointer_cast<DrawViewShell>(mrBase.GetMainViewShell()));
321             if (pDrawViewShell.get() != NULL)
322             {
323                 // Is the edit view in master page mode?
324             	if (pDrawViewShell->GetEditMode() == EM_MASTERPAGE)
325                 {
326                     // Mark the currently edited master page as precious.
327                     SdPage* pCurrentMasterPage = pDrawViewShell->getCurrentPage();
328                     if (pCurrentMasterPage != NULL)
329                         pCurrentMasterPage->SetPrecious(true);
330                 }
331             }
332         }
333     }
334 }
335 
336 
337 
338 
339 } } } // end of namespace ::sd::toolpanel::controls
340