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>
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 <salhelper/thread.hxx>
23 #include <sal/log.hxx>
24 #include <osl/file.hxx>
25 #include <svtools/filechangedchecker.hxx>
26 #include <comphelper/diagnose_ex.hxx>
27 #include <unotools/ucbstreamhelper.hxx>
28 #include <comphelper/processfactory.hxx>
32 #include <com/sun/star/system/SystemShellExecute.hpp>
33 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
35 using namespace css::uno
;
36 using namespace css::system
;
38 ExternalToolEdit::ExternalToolEdit()
42 ExternalToolEdit::~ExternalToolEdit()
46 void ExternalToolEdit::HandleCloseEvent(ExternalToolEdit
* pData
)
50 //import the temp file image stream into the newGraphic
51 std::unique_ptr
<SvStream
> pStream(utl::UcbStreamHelper::CreateStream(pData
->m_aFileName
, StreamMode::READ
));
54 GraphicConverter::Import(*pStream
, newGraphic
);
56 // Now update the Graphic in the shell by re-reading from the newGraphic
57 pData
->Update( newGraphic
);
61 void ExternalToolEdit::StartListeningEvent()
63 //Start an event listener implemented via VCL timeout
65 m_pChecker
.reset(new FileChangedChecker(
66 m_aFileName
, [this] () { return HandleCloseEvent(this); }));
71 // self-destructing thread to make shell execute async
72 class ExternalToolEditThread
73 : public ::salhelper::Thread
76 OUString
const m_aFileName
;
78 virtual void execute() override
;
81 explicit ExternalToolEditThread(OUString aFileName
)
82 : ::salhelper::Thread("ExternalToolEdit")
83 , m_aFileName(std::move(aFileName
))
89 void ExternalToolEditThread::execute()
93 Reference
<XSystemShellExecute
> const xSystemShellExecute(
94 SystemShellExecute::create( ::comphelper::getProcessComponentContext()));
95 xSystemShellExecute
->execute(m_aFileName
, OUString(),
96 SystemShellExecuteFlags::URIS_ONLY
);
98 catch (Exception
const&)
100 TOOLS_WARN_EXCEPTION("svx", "ExternalToolEditThread");
104 void ExternalToolEdit::Edit(GraphicObject
const*const pGraphicObject
)
106 //Get the graphic from the GraphicObject
107 const Graphic
& aGraphic
= pGraphicObject
->GetGraphic();
109 //get the Preferred File Extension for this graphic
111 GraphicHelper::GetPreferredExtension(fExtension
, aGraphic
);
113 //Create the temp File
114 OUString aTempFileBase
;
115 OUString aTempFileName
;
117 osl::FileBase::RC rc
=
118 osl::FileBase::createTempFile(nullptr, nullptr, &aTempFileBase
);
119 if (osl::FileBase::E_None
!= rc
)
121 SAL_WARN("svx", "ExternalToolEdit::Edit: cannot create temp file");
125 // Move it to a file name with image extension properly set
126 aTempFileName
= aTempFileBase
+ "." + fExtension
;
127 // FIXME: this is pretty stupid, need a better osl temp file API
128 rc
= osl::File::move(aTempFileBase
, aTempFileName
);
129 if (osl::FileBase::E_None
!= rc
)
131 SAL_WARN("svx", "ExternalToolEdit::Edit: cannot move temp file");
135 //Write Graphic to the Temp File
136 GraphicFilter
& rGraphicFilter
= GraphicFilter::GetGraphicFilter();
137 sal_uInt16
nFilter(rGraphicFilter
.GetExportFormatNumberForShortName(fExtension
));
139 OUString
aFilter(rGraphicFilter
.GetExportFormatShortName(nFilter
));
141 // Write the Graphic to the file now
142 XOutBitmap::WriteGraphic(aGraphic
, aTempFileName
, aFilter
, XOutFlags::UseNativeIfPossible
| XOutFlags::DontExpandFilename
);
144 // There is a possibility that sPath extension might have been changed if the
145 // provided extension is not writable
146 m_aFileName
= aTempFileName
;
150 rtl::Reference
<ExternalToolEditThread
> const pThread(
151 new ExternalToolEditThread(m_aFileName
));
154 StartListeningEvent();
157 SdrExternalToolEdit::SdrExternalToolEdit(
163 assert(m_pObj
&& m_pView
);
164 StartListening(m_pObj
->getSdrModelFromSdrObject());
168 void SdrExternalToolEdit::Notify(SfxBroadcaster
& rBC
, SfxHint
const& rHint
)
170 if (rHint
.GetId() != SfxHintId::ThisIsAnSdrHint
)
172 SdrHint
const*const pSdrHint(static_cast<SdrHint
const*>(&rHint
));
173 if (SdrHintKind::ModelCleared
== pSdrHint
->GetKind()
174 || (pSdrHint
->GetObject() == m_pObj
.get()
175 && SdrHintKind::ObjectRemoved
== pSdrHint
->GetKind()))
179 m_pChecker
.reset(); // avoid modifying deleted object
184 void SdrExternalToolEdit::Update(Graphic
& rGraphic
)
186 assert(m_pObj
&& m_pView
); // timer should be deleted by Notify() too
187 SdrPageView
*const pPageView
= m_pView
->GetSdrPageView();
191 rtl::Reference
<SdrGrafObj
> pNewObj
= SdrObject::Clone(*m_pObj
, m_pObj
->getSdrModelFromSdrObject());
193 OUString
const description
=
194 m_pView
->GetMarkedObjectList().GetMarkDescription() + " 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 rtl::Reference
<SdrObject
> pOldObj
= m_pObj
;
201 m_pView
->ReplaceObjectAtView(pOldObj
.get(), *pPageView
, pNewObj
.get());
205 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */