1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <svx/extedit.hxx>
12 #include <vcl/svapp.hxx>
13 #include <vcl/graph.hxx>
14 #include <vcl/GraphicObject.hxx>
15 #include <vcl/cvtgrf.hxx>
16 #include <vcl/graphicfilter.hxx>
17 #include <svx/xoutbmp.hxx>
18 #include <svx/graphichelper.hxx>
19 #include <svx/svdpagv.hxx>
20 #include <svx/svdograf.hxx>
21 #include <svx/fmview.hxx>
22 #include <sfx2/viewfrm.hxx>
23 #include <sfx2/bindings.hxx>
24 #include <salhelper/thread.hxx>
25 #include <sal/log.hxx>
26 #include <osl/file.hxx>
27 #include <osl/thread.hxx>
28 #include <osl/process.h>
30 #include <svtools/filechangedchecker.hxx>
31 #include <tools/diagnose_ex.h>
32 #include <unotools/ucbstreamhelper.hxx>
33 #include <comphelper/processfactory.hxx>
37 #include <com/sun/star/system/SystemShellExecute.hpp>
38 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
40 using namespace css::uno
;
41 using namespace css::system
;
43 ExternalToolEdit::ExternalToolEdit()
47 ExternalToolEdit::~ExternalToolEdit()
51 void ExternalToolEdit::HandleCloseEvent(ExternalToolEdit
* pData
)
55 //import the temp file image stream into the newGraphic
56 std::unique_ptr
<SvStream
> pStream(utl::UcbStreamHelper::CreateStream(pData
->m_aFileName
, StreamMode::READ
));
59 GraphicConverter::Import(*pStream
, newGraphic
);
61 // Now update the Graphic in the shell by re-reading from the newGraphic
62 pData
->Update( newGraphic
);
66 void ExternalToolEdit::StartListeningEvent()
68 //Start an event listener implemented via VCL timeout
69 assert(!m_pChecker
.get());
70 m_pChecker
.reset(new FileChangedChecker(
71 m_aFileName
, [this] () { return HandleCloseEvent(this); }));
74 // self-destructing thread to make shell execute async
75 class ExternalToolEditThread
76 : public ::salhelper::Thread
79 OUString
const m_aFileName
;
81 virtual void execute() override
;
84 explicit ExternalToolEditThread(OUString
const& rFileName
)
85 : ::salhelper::Thread("ExternalToolEdit")
86 , m_aFileName(rFileName
)
90 void ExternalToolEditThread::execute()
94 Reference
<XSystemShellExecute
> const xSystemShellExecute(
95 SystemShellExecute::create( ::comphelper::getProcessComponentContext()));
96 xSystemShellExecute
->execute(m_aFileName
, OUString(),
97 SystemShellExecuteFlags::URIS_ONLY
);
99 catch (Exception
const&)
101 TOOLS_WARN_EXCEPTION("svx", "ExternalToolEditThread");
105 void ExternalToolEdit::Edit(GraphicObject
const*const pGraphicObject
)
107 //Get the graphic from the GraphicObject
108 const Graphic
& aGraphic
= pGraphicObject
->GetGraphic();
110 //get the Preferred File Extension for this graphic
112 GraphicHelper::GetPreferredExtension(fExtension
, aGraphic
);
114 //Create the temp File
115 OUString aTempFileBase
;
116 OUString aTempFileName
;
118 osl::FileBase::RC rc
=
119 osl::FileBase::createTempFile(nullptr, nullptr, &aTempFileBase
);
120 if (osl::FileBase::E_None
!= rc
)
122 SAL_WARN("svx", "ExternalToolEdit::Edit: cannot create temp file");
126 // Move it to a file name with image extension properly set
127 aTempFileName
= aTempFileBase
+ "." + fExtension
;
128 // FIXME: this is pretty stupid, need a better osl temp file API
129 rc
= osl::File::move(aTempFileBase
, aTempFileName
);
130 if (osl::FileBase::E_None
!= rc
)
132 SAL_WARN("svx", "ExternalToolEdit::Edit: cannot move temp file");
136 //Write Graphic to the Temp File
137 GraphicFilter
& rGraphicFilter
= GraphicFilter::GetGraphicFilter();
138 sal_uInt16
nFilter(rGraphicFilter
.GetExportFormatNumberForShortName(fExtension
));
140 OUString
aFilter(rGraphicFilter
.GetExportFormatShortName(nFilter
));
142 // Write the Graphic to the file now
143 XOutBitmap::WriteGraphic(aGraphic
, aTempFileName
, aFilter
, XOutFlags::UseNativeIfPossible
| XOutFlags::DontExpandFilename
);
145 // There is a possibility that sPath extension might have been changed if the
146 // provided extension is not writable
147 m_aFileName
= aTempFileName
;
151 rtl::Reference
<ExternalToolEditThread
> const pThread(
152 new ExternalToolEditThread(m_aFileName
));
155 StartListeningEvent();
158 SdrExternalToolEdit::SdrExternalToolEdit(
164 assert(m_pObj
&& m_pView
);
165 StartListening(m_pObj
->getSdrModelFromSdrObject());
169 void SdrExternalToolEdit::Notify(SfxBroadcaster
& rBC
, SfxHint
const& rHint
)
171 if (rHint
.GetId() != SfxHintId::ThisIsAnSdrHint
)
173 SdrHint
const*const pSdrHint(static_cast<SdrHint
const*>(&rHint
));
174 if (SdrHintKind::ModelCleared
== pSdrHint
->GetKind()
175 || (pSdrHint
->GetObject() == m_pObj
176 && SdrHintKind::ObjectRemoved
== pSdrHint
->GetKind()))
180 m_pChecker
.reset(); // avoid modifying deleted object
185 void SdrExternalToolEdit::Update(Graphic
& rGraphic
)
187 assert(m_pObj
&& m_pView
); // timer should be deleted by Notify() too
188 SdrPageView
*const pPageView
= m_pView
->GetSdrPageView();
191 SdrGrafObj
*const pNewObj(static_cast<SdrGrafObj
*>(m_pObj
->CloneSdrObject(m_pObj
->getSdrModelFromSdrObject())));
193 OUString
const description
=
194 m_pView
->GetDescriptionOfMarkedObjects() + " External Edit";
195 m_pView
->BegUndo(description
);
196 pNewObj
->SetGraphicObject(rGraphic
);
197 // set to new object before ReplaceObjectAtView() so that Notify() will
198 // not delete the running timer and crash
199 SdrObject
*const pOldObj
= m_pObj
;
201 m_pView
->ReplaceObjectAtView(pOldObj
, *pPageView
, pNewObj
);
206 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */