diff options
Diffstat (limited to '')
-rw-r--r-- | dbaccess/source/ui/dlg/directsql.cxx | 504 |
1 files changed, 504 insertions, 0 deletions
diff --git a/dbaccess/source/ui/dlg/directsql.cxx b/dbaccess/source/ui/dlg/directsql.cxx new file mode 100644 index 000000000..8cb2a2e2a --- /dev/null +++ b/dbaccess/source/ui/dlg/directsql.cxx @@ -0,0 +1,504 @@ +/* -*- 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 <core_resource.hxx> +#include <directsql.hxx> +#include <strings.hrc> +#include <comphelper/types.hxx> +#include <editeng/colritem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/eeitem.hxx> +#include <osl/mutex.hxx> +#include <svl/itemset.hxx> +#include <svtools/editsyntaxhighlighter.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XMultipleResults.hpp> + +namespace dbaui +{ + SQLEditView::SQLEditView() + { + } + + void SQLEditView::DoBracketHilight(sal_uInt16 nKey) + { + ESelection aCurrentPos = m_xEditView->GetSelection(); + sal_Int32 nStartPos = aCurrentPos.nStartPos; + const sal_uInt32 nStartPara = aCurrentPos.nStartPara; + sal_uInt16 nCount = 0; + int nChar = -1; + + switch (nKey) + { + case '\'': // no break + case '"': + { + nChar = nKey; + break; + } + case '}' : + { + nChar = '{'; + break; + } + case ')': + { + nChar = '('; + break; + } + case ']': + { + nChar = '['; + break; + } + } + + if (nChar == -1) + return; + + bool bUndoEnabled = m_xEditEngine->IsUndoEnabled(); + m_xEditEngine->EnableUndo(false); + + sal_uInt32 nPara = nStartPara; + do + { + if (nPara == nStartPara && nStartPos == 0) + continue; + + OUString aLine( m_xEditEngine->GetText( nPara ) ); + + if (aLine.isEmpty()) + continue; + + for (sal_Int32 i = (nPara==nStartPara) ? nStartPos-1 : aLine.getLength()-1; i>0; --i) + { + if (aLine[i] == nChar) + { + if (!nCount) + { + SfxItemSet aSet(m_xEditEngine->GetEmptyItemSet()); + aSet.Put(SvxColorItem(Color(0,0,0), EE_CHAR_COLOR)); + aSet.Put(SvxWeightItem(WEIGHT_ULTRABOLD, EE_CHAR_WEIGHT)); + aSet.Put(SvxWeightItem(WEIGHT_ULTRABOLD, EE_CHAR_WEIGHT_CJK)); + aSet.Put(SvxWeightItem(WEIGHT_ULTRABOLD, EE_CHAR_WEIGHT_CTL)); + + m_xEditEngine->QuickSetAttribs(aSet, ESelection(nPara, i, nPara, i + 1)); + m_xEditEngine->QuickSetAttribs(aSet, ESelection(nStartPara, nStartPos, nStartPara, nStartPos)); + return; + } + else + --nCount; + } + if (aLine[i] == nKey) + ++nCount; + } + } while (nPara--); + + m_xEditEngine->EnableUndo(bUndoEnabled); + } + + bool SQLEditView::KeyInput(const KeyEvent& rKEvt) + { + DoBracketHilight(rKEvt.GetCharCode()); + return WeldEditView::KeyInput(rKEvt); + } + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::lang; + + constexpr sal_Int32 g_nHistoryLimit = 20; + + // DirectSQLDialog + DirectSQLDialog::DirectSQLDialog(weld::Window* _pParent, const Reference< XConnection >& _rxConn) + : GenericDialogController(_pParent, "dbaccess/ui/directsqldialog.ui", "DirectSQLDialog") + , m_xExecute(m_xBuilder->weld_button("execute")) + , m_xSQLHistory(m_xBuilder->weld_combo_box("sqlhistory")) + , m_xStatus(m_xBuilder->weld_text_view("status")) + , m_xShowOutput(m_xBuilder->weld_check_button("showoutput")) + , m_xOutput(m_xBuilder->weld_text_view("output")) + , m_xClose(m_xBuilder->weld_button("close")) + , m_xSQL(new SQLEditView) + , m_xSQLEd(new weld::CustomWeld(*m_xBuilder, "sql", *m_xSQL)) + , m_aHighlighter(HighlighterLanguage::SQL) + , m_nStatusCount(1) + , m_bInUpdate(false) + , m_xConnection(_rxConn) + , m_pClosingEvent(nullptr) + { + int nWidth = m_xStatus->get_approximate_digit_width() * 60; + int nHeight = m_xStatus->get_height_rows(7); + + m_xSQLEd->set_size_request(nWidth, nHeight); + m_xStatus->set_size_request(-1, nHeight); + m_xOutput->set_size_request(-1, nHeight); + + m_xSQL->GrabFocus(); + + m_xExecute->connect_clicked(LINK(this, DirectSQLDialog, OnExecute)); + m_xClose->connect_clicked(LINK(this, DirectSQLDialog, OnCloseClick)); + m_xSQLHistory->connect_changed(LINK(this, DirectSQLDialog, OnListEntrySelected)); + + // add a dispose listener to the connection + Reference< XComponent > xConnComp(m_xConnection, UNO_QUERY); + OSL_ENSURE(xConnComp.is(), "DirectSQLDialog::DirectSQLDialog: invalid connection!"); + if (xConnComp.is()) + startComponentListening(xConnComp); + + m_xSQL->SetModifyHdl(LINK(this, DirectSQLDialog, OnStatementModified)); + OnStatementModified(nullptr); + + m_aUpdateDataTimer.SetTimeout(300); + m_aUpdateDataTimer.SetInvokeHandler(LINK(this, DirectSQLDialog, ImplUpdateDataHdl)); + } + + DirectSQLDialog::~DirectSQLDialog() + { + ::osl::MutexGuard aGuard(m_aMutex); + if (m_pClosingEvent) + Application::RemoveUserEvent(m_pClosingEvent); + stopAllComponentListening(); + } + + void DirectSQLDialog::_disposing( const EventObject& _rSource ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard(m_aMutex); + + assert(!m_pClosingEvent); + + OSL_ENSURE(Reference< XConnection >(_rSource.Source, UNO_QUERY).get() == m_xConnection.get(), + "DirectSQLDialog::_disposing: where does this come from?"); + + { + OUString sMessage(DBA_RES(STR_DIRECTSQL_CONNECTIONLOST)); + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, + sMessage)); + xError->run(); + } + + m_pClosingEvent = Application::PostUserEvent(LINK(this, DirectSQLDialog, OnClose)); + } + + sal_Int32 DirectSQLDialog::getHistorySize() const + { + CHECK_INVARIANTS("DirectSQLDialog::getHistorySize"); + return m_aStatementHistory.size(); + } + + void DirectSQLDialog::implEnsureHistoryLimit() + { + CHECK_INVARIANTS("DirectSQLDialog::implEnsureHistoryLimit"); + + if (getHistorySize() <= g_nHistoryLimit) + // nothing to do + return; + + sal_Int32 nRemoveEntries = getHistorySize() - g_nHistoryLimit; + while (nRemoveEntries--) + { + m_aStatementHistory.pop_front(); + m_aNormalizedHistory.pop_front(); + m_xSQLHistory->remove(0); + } + } + + void DirectSQLDialog::implAddToStatementHistory(const OUString& _rStatement) + { + CHECK_INVARIANTS("DirectSQLDialog::implAddToStatementHistory"); + + // add the statement to the history + m_aStatementHistory.push_back(_rStatement); + + // normalize the statement, and remember the normalized form, too + OUString sNormalized = _rStatement.replaceAll("\n", " "); + m_aNormalizedHistory.push_back(sNormalized); + + // add the normalized version to the list box + m_xSQLHistory->append_text(sNormalized); + + // ensure that we don't exceed the history limit + implEnsureHistoryLimit(); + } + +#ifdef DBG_UTIL + const char* DirectSQLDialog::impl_CheckInvariants() const + { + if (m_aStatementHistory.size() != m_aNormalizedHistory.size()) + return "statement history is inconsistent!"; + + if (!m_xSQLHistory) + return "invalid listbox!"; + + if (m_aStatementHistory.size() != static_cast<size_t>(m_xSQLHistory->get_count())) + return "invalid listbox entry count!"; + + if (!m_xConnection.is()) + return "have no connection!"; + + return nullptr; + } +#endif + + void DirectSQLDialog::implExecuteStatement(const OUString& _rStatement) + { + CHECK_INVARIANTS("DirectSQLDialog::implExecuteStatement"); + + ::osl::MutexGuard aGuard(m_aMutex); + + OUString sStatus; + + // clear the output box + m_xOutput->set_text(OUString()); + try + { + // create a statement + Reference< XStatement > xStatement = m_xConnection->createStatement(); + + Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData(); + css::uno::Reference< css::sdbc::XMultipleResults > xMR ( xStatement, UNO_QUERY ); + + if (xMeta.is() && xMeta->supportsMultipleResultSets() && xMR.is()) + { + bool hasRS = xStatement->execute(_rStatement); + if(hasRS) + { + css::uno::Reference< css::sdbc::XResultSet > xRS (xMR->getResultSet()); + if (m_xShowOutput->get_active()) + display(xRS); + } + else + addOutputText(OUString::number(xMR->getUpdateCount()) + " rows updated\n"); + for (;;) + { + hasRS = xMR->getMoreResults(); + if (!hasRS && xMR->getUpdateCount() == -1) + break; + if(hasRS) + { + css::uno::Reference< css::sdbc::XResultSet > xRS (xMR->getResultSet()); + if (m_xShowOutput->get_active()) + display(xRS); + } + } + } + else + { + if (_rStatement.toAsciiUpperCase().startsWith("SELECT")) + { + css::uno::Reference< css::sdbc::XResultSet > xRS = xStatement->executeQuery(_rStatement); + if (m_xShowOutput->get_active()) + display(xRS); + } + else + { + sal_Int32 resultCount = xStatement->executeUpdate(_rStatement); + addOutputText(OUString::number(resultCount) + " rows updated\n"); + } + } + // successful + sStatus = DBA_RES(STR_COMMAND_EXECUTED_SUCCESSFULLY); + + // dispose the statement + ::comphelper::disposeComponent(xStatement); + } + catch(const SQLException& e) + { + sStatus = e.Message; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + // add the status text + addStatusText(sStatus); + } + + void DirectSQLDialog::display(const css::uno::Reference< css::sdbc::XResultSet >& xRS) + { + // get a handle for the rows + css::uno::Reference< css::sdbc::XRow > xRow( xRS, css::uno::UNO_QUERY ); + // work through each of the rows + while (xRS->next()) + { + // initialise the output line for each row + OUStringBuffer out; + // work along the columns until that are none left + try + { + int i = 1; + for (;;) + { + // be dumb, treat everything as a string + out.append(xRow->getString(i)).append(","); + i++; + } + } + // trap for when we fall off the end of the row + catch (const SQLException&) + { + } + // report the output + addOutputText(out.makeStringAndClear()); + } + } + + void DirectSQLDialog::addStatusText(const OUString& _rMessage) + { + OUString sAppendMessage = OUString::number(m_nStatusCount++) + ": " + _rMessage + "\n\n"; + + OUString sCompleteMessage = m_xStatus->get_text() + sAppendMessage; + m_xStatus->set_text(sCompleteMessage); + + m_xStatus->select_region(sCompleteMessage.getLength(), sCompleteMessage.getLength()); + } + + void DirectSQLDialog::addOutputText(const OUString& _rMessage) + { + OUString sAppendMessage = _rMessage + "\n"; + + OUString sCompleteMessage = m_xOutput->get_text() + sAppendMessage; + m_xOutput->set_text(sCompleteMessage); + } + + void DirectSQLDialog::executeCurrent() + { + CHECK_INVARIANTS("DirectSQLDialog::executeCurrent"); + + OUString sStatement = m_xSQL->GetText(); + + // execute + implExecuteStatement(sStatement); + + // add the statement to the history + implAddToStatementHistory(sStatement); + + m_xSQL->GrabFocus(); + } + + void DirectSQLDialog::switchToHistory(sal_Int32 _nHistoryPos) + { + CHECK_INVARIANTS("DirectSQLDialog::switchToHistory"); + + if ((_nHistoryPos >= 0) && (_nHistoryPos < getHistorySize())) + { + // set the text in the statement editor + OUString sStatement = m_aStatementHistory[_nHistoryPos]; + m_xSQL->SetText(sStatement); + UpdateData(); + OnStatementModified(nullptr); + + m_xSQL->GrabFocus(); + } + else + OSL_FAIL("DirectSQLDialog::switchToHistory: invalid position!"); + } + + IMPL_LINK_NOARG( DirectSQLDialog, OnStatementModified, LinkParamNone*, void ) + { + if (m_bInUpdate) + return; + + m_xExecute->set_sensitive(!m_xSQL->GetText().isEmpty()); + m_aUpdateDataTimer.Start(); + } + + IMPL_LINK_NOARG( DirectSQLDialog, OnCloseClick, weld::Button&, void ) + { + m_xDialog->response(RET_OK); + } + + IMPL_LINK_NOARG( DirectSQLDialog, OnClose, void*, void ) + { + assert(m_pClosingEvent); + Application::RemoveUserEvent(m_pClosingEvent); + m_pClosingEvent = nullptr; + + m_xDialog->response(RET_OK); + } + + IMPL_LINK_NOARG( DirectSQLDialog, OnExecute, weld::Button&, void ) + { + executeCurrent(); + } + + IMPL_LINK_NOARG( DirectSQLDialog, OnListEntrySelected, weld::ComboBox&, void ) + { + const sal_Int32 nSelected = m_xSQLHistory->get_active(); + if (nSelected != -1) + switchToHistory(nSelected); + } + + Color DirectSQLDialog::GetColorValue(TokenType aToken) + { + return MultiLineEditSyntaxHighlight::GetSyntaxHighlightColor(m_aColorConfig, m_aHighlighter.GetLanguage(), aToken); + } + + IMPL_LINK_NOARG(DirectSQLDialog, ImplUpdateDataHdl, Timer*, void) + { + UpdateData(); + } + + void DirectSQLDialog::UpdateData() + { + m_bInUpdate = true; + EditEngine& rEditEngine = m_xSQL->GetEditEngine(); + + bool bUndoEnabled = rEditEngine.IsUndoEnabled(); + rEditEngine.EnableUndo(false); + + // syntax highlighting + bool bOrigModified = rEditEngine.IsModified(); + for (sal_Int32 nLine=0; nLine < rEditEngine.GetParagraphCount(); ++nLine) + { + OUString aLine( rEditEngine.GetText( nLine ) ); + + ESelection aAllLine(nLine, 0, nLine, EE_TEXTPOS_ALL); + rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_COLOR); + rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_WEIGHT); + rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_WEIGHT_CJK); + rEditEngine.RemoveAttribs(aAllLine, false, EE_CHAR_WEIGHT_CTL); + + std::vector<HighlightPortion> aPortions; + m_aHighlighter.getHighlightPortions( aLine, aPortions ); + for (auto const& portion : aPortions) + { + SfxItemSet aSet(rEditEngine.GetEmptyItemSet()); + aSet.Put(SvxColorItem(GetColorValue(portion.tokenType), EE_CHAR_COLOR)); + rEditEngine.QuickSetAttribs(aSet, ESelection(nLine, portion.nBegin, nLine, portion.nEnd)); + } + } + if (!bOrigModified) + rEditEngine.ClearModifyFlag(); + + rEditEngine.EnableUndo(bUndoEnabled); + + m_bInUpdate = false; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |