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 <vcl/status.hxx> 21 #include <vcl/image.hxx> 22 #include <vcl/timer.hxx> 23 #include <vcl/idle.hxx> 24 #include <vcl/event.hxx> 25 #include <svl/eitem.hxx> 26 #include <sfx2/app.hxx> 27 #include <tools/debug.hxx> 28 29 #include <svx/strings.hrc> 30 #include <svx/modctrl.hxx> 31 #include <svx/dialmgr.hxx> 32 33 #include <com/sun/star/beans/PropertyValue.hpp> 34 #include "modctrl_internal.hxx" 35 #include <bitmaps.hlst> 36 37 using ::com::sun::star::uno::Sequence; 38 using ::com::sun::star::beans::PropertyValue; 39 40 SFX_IMPL_STATUSBAR_CONTROL(SvxModifyControl, SfxBoolItem); 41 42 struct SvxModifyControl::ImplData 43 { 44 enum ModificationState 45 { 46 MODIFICATION_STATE_NO = 0, 47 MODIFICATION_STATE_YES, 48 MODIFICATION_STATE_FEEDBACK, 49 MODIFICATION_STATE_SIZE 50 }; 51 52 Idle maIdle; 53 Image maImages[MODIFICATION_STATE_SIZE]; 54 55 ModificationState mnModState; 56 57 ImplData(): 58 mnModState(MODIFICATION_STATE_NO) 59 { 60 maImages[MODIFICATION_STATE_NO] = Image(StockImage::Yes, RID_SVXBMP_DOC_MODIFIED_NO); 61 maImages[MODIFICATION_STATE_YES] = Image(StockImage::Yes, RID_SVXBMP_DOC_MODIFIED_YES); 62 maImages[MODIFICATION_STATE_FEEDBACK] = Image(StockImage::Yes, RID_SVXBMP_DOC_MODIFIED_FEEDBACK); 63 64 maIdle.SetPriority(TaskPriority::LOWEST); 65 maIdle.SetDebugName("svx::SvxModifyControl maIdle"); 66 } 67 }; 68 69 SvxModifyControl::SvxModifyControl( sal_uInt16 _nSlotId, sal_uInt16 _nId, StatusBar& rStb ) : 70 SfxStatusBarControl( _nSlotId, _nId, rStb ), 71 mxImpl(new ImplData) 72 { 73 mxImpl->maIdle.SetInvokeHandler( LINK(this, SvxModifyControl, OnTimer) ); 74 } 75 76 77 void SvxModifyControl::StateChanged( sal_uInt16, SfxItemState eState, 78 const SfxPoolItem* pState ) 79 { 80 if ( SfxItemState::DEFAULT != eState ) 81 return; 82 83 DBG_ASSERT( dynamic_cast<const SfxBoolItem*>( pState) != nullptr, "invalid item type" ); 84 const SfxBoolItem* pItem = static_cast<const SfxBoolItem*>(pState); 85 mxImpl->maIdle.Stop(); 86 87 bool modified = pItem->GetValue(); 88 bool start = ( !modified && mxImpl->mnModState == ImplData::MODIFICATION_STATE_YES); // should timer be started and feedback image displayed ? 89 90 mxImpl->mnModState = (start ? ImplData::MODIFICATION_STATE_FEEDBACK : (modified ? ImplData::MODIFICATION_STATE_YES : ImplData::MODIFICATION_STATE_NO)); 91 92 _repaint(); 93 94 const char* pResId = modified ? RID_SVXSTR_DOC_MODIFIED_YES : RID_SVXSTR_DOC_MODIFIED_NO; 95 GetStatusBar().SetQuickHelpText(GetId(), SvxResId(pResId)); 96 97 if ( start ) 98 mxImpl->maIdle.Start(); 99 } 100 101 102 IMPL_LINK( SvxModifyControl, OnTimer, Timer *, pTimer, void ) 103 { 104 if (pTimer == nullptr) 105 return; 106 107 pTimer->Stop(); 108 mxImpl->mnModState = ImplData::MODIFICATION_STATE_NO; 109 110 _repaint(); 111 } 112 113 114 void SvxModifyControl::_repaint() 115 { 116 GetStatusBar().SetItemData( GetId(), nullptr ); // force repaint 117 } 118 119 /** 120 * Given a bounding rectangle and an image, determine the top-left position 121 * of the image so that the image would look centered both horizontally and 122 * vertically. 123 * 124 * @param rBoundingRect bounding rectangle 125 * @param rImg image 126 * 127 * @return Point top-left corner of the centered image position 128 */ 129 Point centerImage(const tools::Rectangle& rBoundingRect, const Image& rImg) 130 { 131 Size aImgSize = rImg.GetSizePixel(); 132 Size aRectSize = rBoundingRect.GetSize(); 133 long nXOffset = (aRectSize.getWidth() - aImgSize.getWidth())/2; 134 long nYOffset = (aRectSize.getHeight() - aImgSize.getHeight())/2; 135 Point aPt = rBoundingRect.TopLeft(); 136 aPt += Point(nXOffset, nYOffset); 137 return aPt; 138 } 139 140 void SvxModifyControl::Paint( const UserDrawEvent& rUsrEvt ) 141 { 142 vcl::RenderContext* pDev = rUsrEvt.GetRenderContext(); 143 tools::Rectangle aRect(rUsrEvt.GetRect()); 144 145 ImplData::ModificationState state = mxImpl->mnModState; 146 Point aPt = centerImage(aRect, mxImpl->maImages[state]); 147 pDev->DrawImage(aPt, mxImpl->maImages[state]); 148 } 149 150 void SvxModifyControl::Click() 151 { 152 if (mxImpl->mnModState != ImplData::MODIFICATION_STATE_YES) 153 // document not modified. nothing to do here. 154 return; 155 156 Sequence<PropertyValue> aArgs; 157 execute(".uno:Save", aArgs); 158 } 159 160 161 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 162
