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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "dbfindex.hxx"
21 #include <comphelper/processfactory.hxx>
22 #include <osl/file.hxx>
23 #include <osl/thread.hxx>
24 #include <tools/config.hxx>
25 #include <osl/diagnose.h>
26 #include <unotools/localfilehelper.hxx>
27 #include <tools/urlobj.hxx>
28 #include <unotools/pathoptions.hxx>
29 #include <ucbhelper/content.hxx>
30 #include <svl/filenotation.hxx>
31 #include <rtl/strbuf.hxx>
36 using namespace ::com::sun::star::uno
;
37 using namespace ::com::sun::star::ucb
;
38 using namespace ::svt
;
40 constexpr OStringLiteral
aGroupIdent("dBase III");
43 ODbaseIndexDialog::ODbaseIndexDialog(weld::Window
* pParent
, OUString aDataSrcName
)
44 : GenericDialogController(pParent
, "dbaccess/ui/dbaseindexdialog.ui", "DBaseIndexDialog")
45 , m_aDSN(std::move(aDataSrcName
))
46 , m_xPB_OK(m_xBuilder
->weld_button("ok"))
47 , m_xCB_Tables(m_xBuilder
->weld_combo_box("table"))
48 , m_xIndexes(m_xBuilder
->weld_widget("frame"))
49 , m_xLB_TableIndexes(m_xBuilder
->weld_tree_view("tableindex"))
50 , m_xLB_FreeIndexes(m_xBuilder
->weld_tree_view("freeindex"))
51 , m_xAdd(m_xBuilder
->weld_button("add"))
52 , m_xRemove(m_xBuilder
->weld_button("remove"))
53 , m_xAddAll(m_xBuilder
->weld_button("addall"))
54 , m_xRemoveAll(m_xBuilder
->weld_button("removeall"))
56 int nWidth
= m_xLB_TableIndexes
->get_approximate_digit_width() * 18;
57 int nHeight
= m_xLB_TableIndexes
->get_height_rows(10);
58 m_xLB_TableIndexes
->set_size_request(nWidth
, nHeight
);
59 m_xLB_FreeIndexes
->set_size_request(nWidth
, nHeight
);
61 m_xCB_Tables
->connect_changed( LINK(this, ODbaseIndexDialog
, TableSelectHdl
) );
62 m_xAdd
->connect_clicked( LINK(this, ODbaseIndexDialog
, AddClickHdl
) );
63 m_xRemove
->connect_clicked( LINK(this, ODbaseIndexDialog
, RemoveClickHdl
) );
64 m_xAddAll
->connect_clicked( LINK(this, ODbaseIndexDialog
, AddAllClickHdl
) );
65 m_xRemoveAll
->connect_clicked( LINK(this, ODbaseIndexDialog
, RemoveAllClickHdl
) );
66 m_xPB_OK
->connect_clicked( LINK(this, ODbaseIndexDialog
, OKClickHdl
) );
68 m_xLB_FreeIndexes
->connect_changed( LINK(this, ODbaseIndexDialog
, OnListEntrySelected
) );
69 m_xLB_TableIndexes
->connect_changed( LINK(this, ODbaseIndexDialog
, OnListEntrySelected
) );
75 ODbaseIndexDialog::~ODbaseIndexDialog()
79 void ODbaseIndexDialog::checkButtons()
81 m_xAdd
->set_sensitive(0 != m_xLB_FreeIndexes
->count_selected_rows());
82 m_xAddAll
->set_sensitive(0 != m_xLB_FreeIndexes
->n_children());
84 m_xRemove
->set_sensitive(0 != m_xLB_TableIndexes
->count_selected_rows());
85 m_xRemoveAll
->set_sensitive(0 != m_xLB_TableIndexes
->n_children());
88 OTableIndex
ODbaseIndexDialog::implRemoveIndex(const OUString
& _rName
, TableIndexList
& _rList
, weld::TreeView
& _rDisplay
, bool _bMustExist
)
92 TableIndexList::iterator aSearch
= std::find_if(_rList
.begin(), _rList
.end(),
93 [&_rName
](const OTableIndex
& rIndex
) { return rIndex
.GetIndexFileName() == _rName
; });
94 if (aSearch
!= _rList
.end())
96 sal_Int32 nPos
= static_cast<sal_Int32
>(std::distance(_rList
.begin(), aSearch
));
100 _rList
.erase(aSearch
);
101 _rDisplay
.remove_text(_rName
);
103 // adjust selection if necessary
104 if (static_cast<sal_uInt32
>(nPos
) == _rList
.size())
105 _rDisplay
.select(static_cast<sal_uInt16
>(nPos
)-1);
107 _rDisplay
.select(static_cast<sal_uInt16
>(nPos
));
109 OSL_ENSURE(!_bMustExist
|| !aReturn
.GetIndexFileName().isEmpty(), "ODbaseIndexDialog::implRemoveIndex : did not find the index!");
113 void ODbaseIndexDialog::implInsertIndex(const OTableIndex
& _rIndex
, TableIndexList
& _rList
, weld::TreeView
& _rDisplay
)
115 _rList
.push_front(_rIndex
);
116 _rDisplay
.append_text(_rIndex
.GetIndexFileName());
120 OTableIndex
ODbaseIndexDialog::RemoveTableIndex( std::u16string_view _rTableName
, const OUString
& _rIndexName
)
124 // does the table exist ?
125 TableInfoList::iterator aTablePos
= std::find_if(m_aTableInfoList
.begin(), m_aTableInfoList
.end(),
126 [&] (const OTableInfo
& arg
) { return arg
.aTableName
== _rTableName
; });
128 if (aTablePos
== m_aTableInfoList
.end())
131 return implRemoveIndex(_rIndexName
, aTablePos
->aIndexList
, *m_xLB_TableIndexes
, true/*_bMustExist*/);
134 void ODbaseIndexDialog::InsertTableIndex( std::u16string_view _rTableName
, const OTableIndex
& _rIndex
)
136 TableInfoList::iterator aTablePos
= std::find_if(m_aTableInfoList
.begin(), m_aTableInfoList
.end(),
137 [&] (const OTableInfo
& arg
) { return arg
.aTableName
== _rTableName
; });
139 if (aTablePos
== m_aTableInfoList
.end())
142 implInsertIndex(_rIndex
, aTablePos
->aIndexList
, *m_xLB_TableIndexes
);
145 IMPL_LINK_NOARG(ODbaseIndexDialog
, OKClickHdl
, weld::Button
&, void)
147 // let all tables write their INF file
149 for (auto const& tableInfo
: m_aTableInfoList
)
150 tableInfo
.WriteInfFile(m_aDSN
);
152 m_xDialog
->response(RET_OK
);
155 IMPL_LINK_NOARG(ODbaseIndexDialog
, AddClickHdl
, weld::Button
&, void)
157 OUString aSelection
= m_xLB_FreeIndexes
->get_selected_text();
158 OUString aTableName
= m_xCB_Tables
->get_active_text();
159 OTableIndex aIndex
= RemoveFreeIndex( aSelection
, true );
160 InsertTableIndex( aTableName
, aIndex
);
165 IMPL_LINK_NOARG(ODbaseIndexDialog
, RemoveClickHdl
, weld::Button
&, void)
167 OUString aSelection
= m_xLB_TableIndexes
->get_selected_text();
168 OUString aTableName
= m_xCB_Tables
->get_active_text();
169 OTableIndex aIndex
= RemoveTableIndex( aTableName
, aSelection
);
170 InsertFreeIndex( aIndex
);
175 IMPL_LINK_NOARG(ODbaseIndexDialog
, AddAllClickHdl
, weld::Button
&, void)
177 const sal_Int32 nCnt
= m_xLB_FreeIndexes
->n_children();
178 OUString aTableName
= m_xCB_Tables
->get_active_text();
180 for (sal_Int32 nPos
= 0; nPos
< nCnt
; ++nPos
)
181 InsertTableIndex(aTableName
, RemoveFreeIndex(m_xLB_FreeIndexes
->get_text(0), true));
186 IMPL_LINK_NOARG(ODbaseIndexDialog
, RemoveAllClickHdl
, weld::Button
&, void)
188 const sal_Int32 nCnt
= m_xLB_TableIndexes
->n_children();
189 OUString aTableName
= m_xCB_Tables
->get_active_text();
191 for (sal_Int32 nPos
= 0; nPos
< nCnt
; ++nPos
)
192 InsertFreeIndex(RemoveTableIndex(aTableName
, m_xLB_TableIndexes
->get_text(0)));
197 IMPL_LINK_NOARG(ODbaseIndexDialog
, OnListEntrySelected
, weld::TreeView
&, void)
202 IMPL_LINK(ODbaseIndexDialog
, TableSelectHdl
, weld::ComboBox
&, rComboBox
, void)
205 TableInfoList::iterator aTablePos
= std::find_if(m_aTableInfoList
.begin(), m_aTableInfoList
.end(),
206 [&] (const OTableInfo
& arg
) { return arg
.aTableName
== rComboBox
.get_active_text() ; });
208 if (aTablePos
== m_aTableInfoList
.end())
211 // fill the listbox for the indexes
212 m_xLB_TableIndexes
->clear();
213 for (auto const& index
: aTablePos
->aIndexList
)
214 m_xLB_TableIndexes
->append_text(index
.GetIndexFileName());
216 if (!aTablePos
->aIndexList
.empty())
217 m_xLB_TableIndexes
->select(0);
222 void ODbaseIndexDialog::Init()
224 m_xPB_OK
->set_sensitive(false);
225 m_xIndexes
->set_sensitive(false);
227 // All indices are first added to a list of free indices.
228 // Afterwards, check the index of each table in the Inf-file.
229 // These indices are removed from the list of free indices and
230 // entered in the indexlist of the table.
232 // if the string does not contain a path, cut the string
234 aURL
.SetSmartProtocol(INetProtocol::File
);
236 SvtPathOptions aPathOptions
;
237 m_aDSN
= aPathOptions
.SubstituteVariable(m_aDSN
);
239 aURL
.SetSmartURL(m_aDSN
);
241 // String aFileName = aURL.PathToFileName();
242 m_aDSN
= aURL
.GetMainURL(INetURLObject::DecodeMechanism::NONE
);
243 ::ucbhelper::Content aFile
;
247 aFile
= ::ucbhelper::Content(m_aDSN
,Reference
< css::ucb::XCommandEnvironment
>(), comphelper::getProcessComponentContext());
248 bFolder
= aFile
.isFolder();
255 // first assume for all indexes they're free
257 OUString
const aIndexExt("ndx");
258 OUString
const aTableExt("dbf");
260 std::vector
< OUString
> aUsedIndexes
;
262 aURL
.SetSmartProtocol(INetProtocol::File
);
263 const Sequence
<OUString
> aFolderUrls
= ::utl::LocalFileHelper::GetFolderContents(m_aDSN
, bFolder
);
264 for(const OUString
& rURL
: aFolderUrls
)
267 osl::FileBase::getSystemPathFromFileURL(rURL
,aName
);
268 aURL
.SetSmartURL(aName
);
269 OUString aExt
= aURL
.getExtension();
270 if (aExt
== aIndexExt
)
272 m_aFreeIndexList
.emplace_back(aURL
.getName() );
274 else if (aExt
== aTableExt
)
276 m_aTableInfoList
.emplace_back(aURL
.getName() );
277 OTableInfo
& rTabInfo
= m_aTableInfoList
.back();
280 aURL
.setExtension(u
"inf");
281 OFileNotation
aTransformer(aURL
.GetURLNoPass(), OFileNotation::N_URL
);
282 Config
aInfFile( aTransformer
.get(OFileNotation::N_SYSTEM
) );
283 aInfFile
.SetGroup( aGroupIdent
);
285 // fill the indexes list
287 sal_uInt16 nKeyCnt
= aInfFile
.GetKeyCount();
291 for( sal_uInt16 nKey
= 0; nKey
< nKeyCnt
; nKey
++ )
293 // does the key point to an index file ?
294 aKeyName
= aInfFile
.GetKeyName( nKey
);
295 aNDX
= aKeyName
.copy(0,3);
297 // yes -> add to the tables index list
300 aEntry
= OStringToOUString(aInfFile
.ReadKey(aKeyName
), osl_getThreadTextEncoding());
301 rTabInfo
.aIndexList
.emplace_back( aEntry
);
303 // and remove it from the free index list
304 aUsedIndexes
.push_back(aEntry
);
305 // do this later below. We may not have encountered the index file, yet, thus we may not
306 // know the index as being free, yet
312 for (auto const& usedIndex
: aUsedIndexes
)
313 RemoveFreeIndex( usedIndex
, false );
315 if (!m_aTableInfoList
.empty())
317 m_xPB_OK
->set_sensitive(true);
318 m_xIndexes
->set_sensitive(true);
324 void ODbaseIndexDialog::SetCtrls()
327 for (auto const& tableInfo
: m_aTableInfoList
)
328 m_xCB_Tables
->append_text(tableInfo
.aTableName
);
330 // put the first dataset into Edit
331 if (!m_aTableInfoList
.empty())
333 const OTableInfo
& rTabInfo
= m_aTableInfoList
.front();
334 m_xCB_Tables
->set_entry_text(rTabInfo
.aTableName
);
336 // build ListBox of the table indices
337 for (auto const& index
: rTabInfo
.aIndexList
)
338 m_xLB_TableIndexes
->append_text(index
.GetIndexFileName());
340 if (!rTabInfo
.aIndexList
.empty())
341 m_xLB_TableIndexes
->select(0);
344 // ListBox of the free indices
345 for (auto const& freeIndex
: m_aFreeIndexList
)
346 m_xLB_FreeIndexes
->append_text(freeIndex
.GetIndexFileName());
348 if (!m_aFreeIndexList
.empty())
349 m_xLB_FreeIndexes
->select(0);
351 TableSelectHdl(*m_xCB_Tables
);
355 void OTableInfo::WriteInfFile( const OUString
& rDSN
) const
359 aURL
.SetSmartProtocol(INetProtocol::File
);
360 OUString aDsn
= rDSN
;
362 SvtPathOptions aPathOptions
;
363 aDsn
= aPathOptions
.SubstituteVariable(aDsn
);
365 aURL
.SetSmartURL(aDsn
);
366 aURL
.Append(aTableName
);
367 aURL
.setExtension(u
"inf");
369 OFileNotation
aTransformer(aURL
.GetURLNoPass(), OFileNotation::N_URL
);
370 Config
aInfFile( aTransformer
.get(OFileNotation::N_SYSTEM
) );
371 aInfFile
.SetGroup( aGroupIdent
);
373 // first, delete all table indices
375 sal_uInt16 nKeyCnt
= aInfFile
.GetKeyCount();
378 while( nKey
< nKeyCnt
)
380 // Does the key point to an index file?...
381 OString aKeyName
= aInfFile
.GetKeyName( nKey
);
382 aNDX
= aKeyName
.copy(0,3);
384 //...if yes, delete index file, nKey is at subsequent key
387 aInfFile
.DeleteKey(aKeyName
);
395 // now add all saved indices
397 for (auto const& index
: aIndexList
)
399 OStringBuffer
aKeyName("NDX");
400 if( nPos
> 0 ) // first index contains no number
401 aKeyName
.append(static_cast<sal_Int32
>(nPos
));
403 aKeyName
.makeStringAndClear(),
404 OUStringToOString(index
.GetIndexFileName(),
405 osl_getThreadTextEncoding()));
411 // if only [dbase] is left in INF-file, delete file
417 ::ucbhelper::Content
aContent(aURL
.GetURLNoPass(),Reference
<XCommandEnvironment
>(), comphelper::getProcessComponentContext());
418 aContent
.executeCommand( "delete", Any( true ) );
420 catch (const Exception
& )
422 // simply silent this. The strange algorithm here does a lot of
423 // things even if no files at all were created or accessed, so it's
424 // possible that the file we're trying to delete does not even
425 // exist, and this is a valid condition.
431 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */