427 lines
14 KiB
C++
427 lines
14 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include "dbfindex.hxx"
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <osl/file.hxx>
|
|
#include <osl/thread.hxx>
|
|
#include <tools/config.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <unotools/localfilehelper.hxx>
|
|
#include <tools/urlobj.hxx>
|
|
#include <unotools/pathoptions.hxx>
|
|
#include <ucbhelper/content.hxx>
|
|
#include <svl/filenotation.hxx>
|
|
#include <rtl/strbuf.hxx>
|
|
#include <utility>
|
|
|
|
namespace dbaui
|
|
{
|
|
using namespace ::com::sun::star::uno;
|
|
using namespace ::com::sun::star::ucb;
|
|
using namespace ::svt;
|
|
|
|
constexpr OString aGroupIdent("dBase III"_ostr);
|
|
|
|
|
|
ODbaseIndexDialog::ODbaseIndexDialog(weld::Window * pParent, OUString aDataSrcName)
|
|
: GenericDialogController(pParent, u"dbaccess/ui/dbaseindexdialog.ui"_ustr, u"DBaseIndexDialog"_ustr)
|
|
, m_aDSN(std::move(aDataSrcName))
|
|
, m_xPB_OK(m_xBuilder->weld_button(u"ok"_ustr))
|
|
, m_xCB_Tables(m_xBuilder->weld_combo_box(u"table"_ustr))
|
|
, m_xIndexes(m_xBuilder->weld_widget(u"frame"_ustr))
|
|
, m_xLB_TableIndexes(m_xBuilder->weld_tree_view(u"tableindex"_ustr))
|
|
, m_xLB_FreeIndexes(m_xBuilder->weld_tree_view(u"freeindex"_ustr))
|
|
, m_xAdd(m_xBuilder->weld_button(u"add"_ustr))
|
|
, m_xRemove(m_xBuilder->weld_button(u"remove"_ustr))
|
|
, m_xAddAll(m_xBuilder->weld_button(u"addall"_ustr))
|
|
, m_xRemoveAll(m_xBuilder->weld_button(u"removeall"_ustr))
|
|
{
|
|
int nWidth = m_xLB_TableIndexes->get_approximate_digit_width() * 18;
|
|
int nHeight = m_xLB_TableIndexes->get_height_rows(10);
|
|
m_xLB_TableIndexes->set_size_request(nWidth, nHeight);
|
|
m_xLB_FreeIndexes->set_size_request(nWidth, nHeight);
|
|
|
|
m_xCB_Tables->connect_changed( LINK(this, ODbaseIndexDialog, TableSelectHdl) );
|
|
m_xAdd->connect_clicked( LINK(this, ODbaseIndexDialog, AddClickHdl) );
|
|
m_xRemove->connect_clicked( LINK(this, ODbaseIndexDialog, RemoveClickHdl) );
|
|
m_xAddAll->connect_clicked( LINK(this, ODbaseIndexDialog, AddAllClickHdl) );
|
|
m_xRemoveAll->connect_clicked( LINK(this, ODbaseIndexDialog, RemoveAllClickHdl) );
|
|
m_xPB_OK->connect_clicked( LINK(this, ODbaseIndexDialog, OKClickHdl) );
|
|
|
|
m_xLB_FreeIndexes->connect_changed( LINK(this, ODbaseIndexDialog, OnListEntrySelected) );
|
|
m_xLB_TableIndexes->connect_changed( LINK(this, ODbaseIndexDialog, OnListEntrySelected) );
|
|
|
|
Init();
|
|
SetCtrls();
|
|
}
|
|
|
|
ODbaseIndexDialog::~ODbaseIndexDialog()
|
|
{
|
|
}
|
|
|
|
void ODbaseIndexDialog::checkButtons()
|
|
{
|
|
m_xAdd->set_sensitive(0 != m_xLB_FreeIndexes->count_selected_rows());
|
|
m_xAddAll->set_sensitive(0 != m_xLB_FreeIndexes->n_children());
|
|
|
|
m_xRemove->set_sensitive(0 != m_xLB_TableIndexes->count_selected_rows());
|
|
m_xRemoveAll->set_sensitive(0 != m_xLB_TableIndexes->n_children());
|
|
}
|
|
|
|
OTableIndex ODbaseIndexDialog::implRemoveIndex(const OUString& _rName, TableIndexList& _rList, weld::TreeView& _rDisplay, bool _bMustExist)
|
|
{
|
|
OTableIndex aReturn;
|
|
|
|
TableIndexList::iterator aSearch = std::find_if(_rList.begin(), _rList.end(),
|
|
[&_rName](const OTableIndex& rIndex) { return rIndex.GetIndexFileName() == _rName; });
|
|
if (aSearch != _rList.end())
|
|
{
|
|
sal_Int32 nPos = static_cast<sal_Int32>(std::distance(_rList.begin(), aSearch));
|
|
|
|
aReturn = *aSearch;
|
|
|
|
_rList.erase(aSearch);
|
|
_rDisplay.remove_text(_rName);
|
|
|
|
// adjust selection if necessary
|
|
if (static_cast<sal_uInt32>(nPos) == _rList.size())
|
|
_rDisplay.select(static_cast<sal_uInt16>(nPos)-1);
|
|
else
|
|
_rDisplay.select(static_cast<sal_uInt16>(nPos));
|
|
}
|
|
OSL_ENSURE(!_bMustExist || !aReturn.GetIndexFileName().isEmpty(), "ODbaseIndexDialog::implRemoveIndex : did not find the index!");
|
|
return aReturn;
|
|
}
|
|
|
|
void ODbaseIndexDialog::implInsertIndex(const OTableIndex& _rIndex, TableIndexList& _rList, weld::TreeView& _rDisplay)
|
|
{
|
|
_rList.push_front(_rIndex);
|
|
_rDisplay.append_text(_rIndex.GetIndexFileName());
|
|
_rDisplay.select(0);
|
|
}
|
|
|
|
OTableIndex ODbaseIndexDialog::RemoveTableIndex( std::u16string_view _rTableName, const OUString& _rIndexName )
|
|
{
|
|
OTableIndex aReturn;
|
|
|
|
// does the table exist ?
|
|
TableInfoList::iterator aTablePos = std::find_if(m_aTableInfoList.begin(), m_aTableInfoList.end(),
|
|
[&] (const OTableInfo& arg) { return arg.aTableName == _rTableName; });
|
|
|
|
if (aTablePos == m_aTableInfoList.end())
|
|
return aReturn;
|
|
|
|
return implRemoveIndex(_rIndexName, aTablePos->aIndexList, *m_xLB_TableIndexes, true/*_bMustExist*/);
|
|
}
|
|
|
|
void ODbaseIndexDialog::InsertTableIndex( std::u16string_view _rTableName, const OTableIndex& _rIndex)
|
|
{
|
|
TableInfoList::iterator aTablePos = std::find_if(m_aTableInfoList.begin(), m_aTableInfoList.end(),
|
|
[&] (const OTableInfo& arg) { return arg.aTableName == _rTableName; });
|
|
|
|
if (aTablePos == m_aTableInfoList.end())
|
|
return;
|
|
|
|
implInsertIndex(_rIndex, aTablePos->aIndexList, *m_xLB_TableIndexes);
|
|
}
|
|
|
|
IMPL_LINK_NOARG(ODbaseIndexDialog, OKClickHdl, weld::Button&, void)
|
|
{
|
|
// let all tables write their INF file
|
|
|
|
for (auto const& tableInfo : m_aTableInfoList)
|
|
tableInfo.WriteInfFile(m_aDSN);
|
|
|
|
m_xDialog->response(RET_OK);
|
|
}
|
|
|
|
IMPL_LINK_NOARG(ODbaseIndexDialog, AddClickHdl, weld::Button&, void)
|
|
{
|
|
OUString aSelection = m_xLB_FreeIndexes->get_selected_text();
|
|
OUString aTableName = m_xCB_Tables->get_active_text();
|
|
OTableIndex aIndex = RemoveFreeIndex( aSelection, true );
|
|
InsertTableIndex( aTableName, aIndex );
|
|
|
|
checkButtons();
|
|
}
|
|
|
|
IMPL_LINK_NOARG(ODbaseIndexDialog, RemoveClickHdl, weld::Button&, void)
|
|
{
|
|
OUString aSelection = m_xLB_TableIndexes->get_selected_text();
|
|
OUString aTableName = m_xCB_Tables->get_active_text();
|
|
OTableIndex aIndex = RemoveTableIndex( aTableName, aSelection );
|
|
InsertFreeIndex( aIndex );
|
|
|
|
checkButtons();
|
|
}
|
|
|
|
IMPL_LINK_NOARG(ODbaseIndexDialog, AddAllClickHdl, weld::Button&, void)
|
|
{
|
|
const sal_Int32 nCnt = m_xLB_FreeIndexes->n_children();
|
|
OUString aTableName = m_xCB_Tables->get_active_text();
|
|
|
|
for (sal_Int32 nPos = 0; nPos < nCnt; ++nPos)
|
|
InsertTableIndex(aTableName, RemoveFreeIndex(m_xLB_FreeIndexes->get_text(0), true));
|
|
|
|
checkButtons();
|
|
}
|
|
|
|
IMPL_LINK_NOARG(ODbaseIndexDialog, RemoveAllClickHdl, weld::Button&, void)
|
|
{
|
|
const sal_Int32 nCnt = m_xLB_TableIndexes->n_children();
|
|
OUString aTableName = m_xCB_Tables->get_active_text();
|
|
|
|
for (sal_Int32 nPos = 0; nPos < nCnt; ++nPos)
|
|
InsertFreeIndex(RemoveTableIndex(aTableName, m_xLB_TableIndexes->get_text(0)));
|
|
|
|
checkButtons();
|
|
}
|
|
|
|
IMPL_LINK_NOARG(ODbaseIndexDialog, OnListEntrySelected, weld::TreeView&, void)
|
|
{
|
|
checkButtons();
|
|
}
|
|
|
|
IMPL_LINK(ODbaseIndexDialog, TableSelectHdl, weld::ComboBox&, rComboBox, void)
|
|
{
|
|
// search the table
|
|
TableInfoList::iterator aTablePos = std::find_if(m_aTableInfoList.begin(), m_aTableInfoList.end(),
|
|
[&] (const OTableInfo& arg) { return arg.aTableName == rComboBox.get_active_text() ; });
|
|
|
|
if (aTablePos == m_aTableInfoList.end())
|
|
return;
|
|
|
|
// fill the listbox for the indexes
|
|
m_xLB_TableIndexes->clear();
|
|
for (auto const& index : aTablePos->aIndexList)
|
|
m_xLB_TableIndexes->append_text(index.GetIndexFileName());
|
|
|
|
if (!aTablePos->aIndexList.empty())
|
|
m_xLB_TableIndexes->select(0);
|
|
|
|
checkButtons();
|
|
}
|
|
|
|
void ODbaseIndexDialog::Init()
|
|
{
|
|
m_xPB_OK->set_sensitive(false);
|
|
m_xIndexes->set_sensitive(false);
|
|
|
|
// All indices are first added to a list of free indices.
|
|
// Afterwards, check the index of each table in the Inf-file.
|
|
// These indices are removed from the list of free indices and
|
|
// entered in the indexlist of the table.
|
|
|
|
// if the string does not contain a path, cut the string
|
|
INetURLObject aURL;
|
|
aURL.SetSmartProtocol(INetProtocol::File);
|
|
{
|
|
SvtPathOptions aPathOptions;
|
|
m_aDSN = aPathOptions.SubstituteVariable(m_aDSN);
|
|
}
|
|
aURL.SetSmartURL(m_aDSN);
|
|
|
|
// String aFileName = aURL.PathToFileName();
|
|
m_aDSN = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
|
|
::ucbhelper::Content aFile;
|
|
bool bFolder=true;
|
|
try
|
|
{
|
|
aFile = ::ucbhelper::Content(m_aDSN,Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext());
|
|
bFolder = aFile.isFolder();
|
|
}
|
|
catch(Exception&)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// first assume for all indexes they're free
|
|
|
|
std::vector< OUString > aUsedIndexes;
|
|
|
|
aURL.SetSmartProtocol(INetProtocol::File);
|
|
const Sequence<OUString> aFolderUrls = ::utl::LocalFileHelper::GetFolderContents(m_aDSN, bFolder);
|
|
for(const OUString& rURL : aFolderUrls)
|
|
{
|
|
OUString aName;
|
|
osl::FileBase::getSystemPathFromFileURL(rURL,aName);
|
|
aURL.SetSmartURL(aName);
|
|
OUString aExt = aURL.getExtension();
|
|
if (aExt == "ndx")
|
|
{
|
|
m_aFreeIndexList.emplace_back(aURL.getName() );
|
|
}
|
|
else if (aExt == "dbf")
|
|
{
|
|
m_aTableInfoList.emplace_back(aURL.getName() );
|
|
OTableInfo& rTabInfo = m_aTableInfoList.back();
|
|
|
|
// open the INF file
|
|
aURL.setExtension(u"inf");
|
|
OFileNotation aTransformer(aURL.GetURLNoPass(), OFileNotation::N_URL);
|
|
Config aInfFile( aTransformer.get(OFileNotation::N_SYSTEM) );
|
|
aInfFile.SetGroup( aGroupIdent );
|
|
|
|
// fill the indexes list
|
|
OString aNDX;
|
|
sal_uInt16 nKeyCnt = aInfFile.GetKeyCount();
|
|
OString aKeyName;
|
|
OUString aEntry;
|
|
|
|
for( sal_uInt16 nKey = 0; nKey < nKeyCnt; nKey++ )
|
|
{
|
|
// does the key point to an index file ?
|
|
aKeyName = aInfFile.GetKeyName( nKey );
|
|
aNDX = aKeyName.copy(0,3);
|
|
|
|
// yes -> add to the tables index list
|
|
if (aNDX == "NDX")
|
|
{
|
|
aEntry = OStringToOUString(aInfFile.ReadKey(aKeyName), osl_getThreadTextEncoding());
|
|
rTabInfo.aIndexList.emplace_back( aEntry );
|
|
|
|
// and remove it from the free index list
|
|
aUsedIndexes.push_back(aEntry);
|
|
// do this later below. We may not have encountered the index file, yet, thus we may not
|
|
// know the index as being free, yet
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto const& usedIndex : aUsedIndexes)
|
|
RemoveFreeIndex( usedIndex, false );
|
|
|
|
if (!m_aTableInfoList.empty())
|
|
{
|
|
m_xPB_OK->set_sensitive(true);
|
|
m_xIndexes->set_sensitive(true);
|
|
}
|
|
|
|
checkButtons();
|
|
}
|
|
|
|
void ODbaseIndexDialog::SetCtrls()
|
|
{
|
|
// ComboBox tables
|
|
for (auto const& tableInfo : m_aTableInfoList)
|
|
m_xCB_Tables->append_text(tableInfo.aTableName);
|
|
|
|
// put the first dataset into Edit
|
|
if (!m_aTableInfoList.empty())
|
|
{
|
|
const OTableInfo& rTabInfo = m_aTableInfoList.front();
|
|
m_xCB_Tables->set_entry_text(rTabInfo.aTableName);
|
|
|
|
// build ListBox of the table indices
|
|
for (auto const& index : rTabInfo.aIndexList)
|
|
m_xLB_TableIndexes->append_text(index.GetIndexFileName());
|
|
|
|
if (!rTabInfo.aIndexList.empty())
|
|
m_xLB_TableIndexes->select(0);
|
|
}
|
|
|
|
// ListBox of the free indices
|
|
for (auto const& freeIndex : m_aFreeIndexList)
|
|
m_xLB_FreeIndexes->append_text(freeIndex.GetIndexFileName());
|
|
|
|
if (!m_aFreeIndexList.empty())
|
|
m_xLB_FreeIndexes->select(0);
|
|
|
|
TableSelectHdl(*m_xCB_Tables);
|
|
checkButtons();
|
|
}
|
|
|
|
void OTableInfo::WriteInfFile( const OUString& rDSN ) const
|
|
{
|
|
// open INF file
|
|
INetURLObject aURL;
|
|
aURL.SetSmartProtocol(INetProtocol::File);
|
|
OUString aDsn = rDSN;
|
|
{
|
|
SvtPathOptions aPathOptions;
|
|
aDsn = aPathOptions.SubstituteVariable(aDsn);
|
|
}
|
|
aURL.SetSmartURL(aDsn);
|
|
aURL.Append(aTableName);
|
|
aURL.setExtension(u"inf");
|
|
|
|
OFileNotation aTransformer(aURL.GetURLNoPass(), OFileNotation::N_URL);
|
|
Config aInfFile( aTransformer.get(OFileNotation::N_SYSTEM) );
|
|
aInfFile.SetGroup( aGroupIdent );
|
|
|
|
// first, delete all table indices
|
|
sal_uInt16 nKeyCnt = aInfFile.GetKeyCount();
|
|
sal_uInt16 nKey = 0;
|
|
|
|
while( nKey < nKeyCnt )
|
|
{
|
|
// Does the key point to an index file?...
|
|
OString aKeyName = aInfFile.GetKeyName( nKey );
|
|
OString aNDX = aKeyName.copy(0,3);
|
|
|
|
//...if yes, delete index file, nKey is at subsequent key
|
|
if (aNDX == "NDX")
|
|
{
|
|
aInfFile.DeleteKey(aKeyName);
|
|
nKeyCnt--;
|
|
}
|
|
else
|
|
nKey++;
|
|
|
|
}
|
|
|
|
// now add all saved indices
|
|
sal_uInt16 nPos = 0;
|
|
for (auto const& index : aIndexList)
|
|
{
|
|
OStringBuffer aKeyName("NDX");
|
|
if( nPos > 0 ) // first index contains no number
|
|
aKeyName.append(static_cast<sal_Int32>(nPos));
|
|
aInfFile.WriteKey(
|
|
aKeyName.makeStringAndClear(),
|
|
OUStringToOString(index.GetIndexFileName(),
|
|
osl_getThreadTextEncoding()));
|
|
++nPos;
|
|
}
|
|
|
|
aInfFile.Flush();
|
|
|
|
// if only [dbase] is left in INF-file, delete file
|
|
if(nPos)
|
|
return;
|
|
|
|
try
|
|
{
|
|
::ucbhelper::Content aContent(aURL.GetURLNoPass(),Reference<XCommandEnvironment>(), comphelper::getProcessComponentContext());
|
|
aContent.executeCommand( u"delete"_ustr, Any( true ) );
|
|
}
|
|
catch (const Exception& )
|
|
{
|
|
// simply silent this. The strange algorithm here does a lot of
|
|
// things even if no files at all were created or accessed, so it's
|
|
// possible that the file we're trying to delete does not even
|
|
// exist, and this is a valid condition.
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|