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/graph.hxx>
13 #include <vcl/GraphicObject.hxx>
14 #include <vcl/cvtgrf.hxx>
15 #include <vcl/graphicfilter.hxx>
16 #include <svx/xoutbmp.hxx>
17 #include <svx/graphichelper.hxx>
18 #include <svx/svdpagv.hxx>
19 #include <svx/svdograf.hxx>
20 #include <svx/fmview.hxx>
21 #include <salhelper/thread.hxx>
22 #include <sal/log.hxx>
23 #include <osl/file.hxx>
24 #include <svtools/filechangedchecker.hxx>
25 #include <tools/diagnose_ex.h>
26 #include <unotools/ucbstreamhelper.hxx>
27 #include <comphelper/processfactory.hxx>
31 #include <com/sun/star/system/SystemShellExecute.hpp>
32 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
34 using namespace css::uno
;
35 using namespace css::system
;
37 ExternalToolEdit::ExternalToolEdit()
41 ExternalToolEdit::~ExternalToolEdit()
45 void ExternalToolEdit::HandleCloseEvent(ExternalToolEdit
* pData
)
49 //import the temp file image stream into the newGraphic
50 std::unique_ptr
<SvStream
> pStream(utl::UcbStreamHelper::CreateStream(pData
->m_aFileName
, StreamMode::READ
));
53 GraphicConverter::Import(*pStream
, newGraphic
);
55 // Now update the Graphic in the shell by re-reading from the newGraphic
56 pData
->Update( newGraphic
);
60 void ExternalToolEdit::StartListeningEvent()
62 //Start an event listener implemented via VCL timeout
64 m_pChecker
.reset(new FileChangedChecker(
65 m_aFileName
, [this] () { return HandleCloseEvent(this); }));
70 // self-destructing thread to make shell execute async
71 class ExternalToolEditThread
72 : public ::salhelper::Thread
75 OUString
const m_aFileName
;
77 virtual void execute() override
;
80 explicit ExternalToolEditThread(OUString
const& rFileName
)
81 : ::salhelper::Thread("ExternalToolEdit")
82 , m_aFileName(rFileName
)
88 void ExternalToolEditThread::execute()
92 Reference
<XSystemShellExecute
> const xSystemShellExecute(
93 SystemShellExecute::create( ::comphelper::getProcessComponentContext()));
94 xSystemShellExecute
->execute(m_aFileName
, OUString(),
95 SystemShellExecuteFlags::URIS_ONLY
);
97 catch (Exception
const&)
99 TOOLS_WARN_EXCEPTION("svx", "ExternalToolEditThread");
103 void ExternalToolEdit::Edit(GraphicObject
const*const pGraphicObject
)
105 //Get the graphic from the GraphicObject
106 const Graphic
& aGraphic
= pGraphicObject
->GetGraphic();
108 //get the Preferred File Extension for this graphic
110 GraphicHelper::GetPreferredExtension(fExtension
, aGraphic
);
112 //Create the temp File
113 OUString aTempFileBase
;
114 OUString aTempFileName
;
116 osl::FileBase::RC rc
=
117 osl::FileBase::createTempFile(nullptr, nullptr, &aTempFileBase
);
118 if (osl::FileBase::E_None
!= rc
)
120 SAL_WARN("svx", "ExternalToolEdit::Edit: cannot create temp file");
124 // Move it to a file name with image extension properly set
125 aTempFileName
= aTempFileBase
+ "." + fExtension
;
126 // FIXME: this is pretty stupid, need a better osl temp file API
127 rc
= osl::File::move(aTempFileBase
, aTempFileName
);
128 if (osl::FileBase::E_None
!= rc
)
130 SAL_WARN("svx", "ExternalToolEdit::Edit: cannot move temp file");
134 //Write Graphic to the Temp File
135 GraphicFilter
& rGraphicFilter
= GraphicFilter::GetGraphicFilter();
136 sal_uInt16
nFilter(rGraphicFilter
.GetExportFormatNumberForShortName(fExtension
));
138 OUString
aFilter(rGraphicFilter
.GetExportFormatShortName(nFilter
));
140 // Write the Graphic to the file now
141 XOutBitmap::WriteGraphic(aGraphic
, aTempFileName
, aFilter
, XOutFlags::UseNativeIfPossible
| XOutFlags::DontExpandFilename
);
143 // There is a possibility that sPath extension might have been changed if the
144 // provided extension is not writable
145 m_aFileName
= aTempFileName
;
149 rtl::Reference
<ExternalToolEditThread
> const pThread(
150 new ExternalToolEditThread(m_aFileName
));
153 StartListeningEvent();
156 SdrExternalToolEdit::SdrExternalToolEdit(
162 assert(m_pObj
&& m_pView
);
163 StartListening(m_pObj
->getSdrModelFromSdrObject());
167 void SdrExternalToolEdit::Notify(SfxBroadcaster
& rBC
, SfxHint
const& rHint
)
169 if (rHint
.GetId() != SfxHintId::ThisIsAnSdrHint
)
171 SdrHint
const*const pSdrHint(static_cast<SdrHint
const*>(&rHint
));
172 if (SdrHintKind::ModelCleared
== pSdrHint
->GetKind()
173 || (pSdrHint
->GetObject() == m_pObj
174 && SdrHintKind::ObjectRemoved
== pSdrHint
->GetKind()))
178 m_pChecker
.reset(); // avoid modifying deleted object
183 void SdrExternalToolEdit::Update(Graphic
& rGraphic
)
185 assert(m_pObj
&& m_pView
); // timer should be deleted by Notify() too
186 SdrPageView
*const pPageView
= m_pView
->GetSdrPageView();
190 SdrGrafObj
*const pNewObj(static_cast<SdrGrafObj
*>(m_pObj
->CloneSdrObject(m_pObj
->getSdrModelFromSdrObject())));
192 OUString
const description
=
193 m_pView
->GetDescriptionOfMarkedObjects() + " External Edit";
194 m_pView
->BegUndo(description
);
195 pNewObj
->SetGraphicObject(rGraphic
);
196 // set to new object before ReplaceObjectAtView() so that Notify() will
197 // not delete the running timer and crash
198 SdrObject
*const pOldObj
= m_pObj
;
200 m_pView
->ReplaceObjectAtView(pOldObj
, *pPageView
, pNewObj
);
204 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */