1495 lines
52 KiB
C++
1495 lines
52 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 <hangulhanjadlg.hxx>
|
|
#include <dialmgr.hxx>
|
|
|
|
#include <helpids.h>
|
|
#include <strings.hrc>
|
|
|
|
#include <algorithm>
|
|
#include <sal/log.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <tools/debug.hxx>
|
|
#include <i18nlangtag/languagetag.hxx>
|
|
#include <vcl/virdev.hxx>
|
|
#include <vcl/weldutils.hxx>
|
|
#include <unotools/lingucfg.hxx>
|
|
#include <unotools/linguprops.hxx>
|
|
#include <com/sun/star/lang/NoSupportException.hpp>
|
|
#include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
|
|
#include <com/sun/star/linguistic2/ConversionDirection.hpp>
|
|
#include <com/sun/star/linguistic2/ConversionDictionaryList.hpp>
|
|
#include <com/sun/star/i18n/TextConversionOption.hpp>
|
|
#include <com/sun/star/util/XFlushable.hpp>
|
|
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <comphelper/string.hxx>
|
|
|
|
#define HHC editeng::HangulHanjaConversion
|
|
#define LINE_CNT static_cast< sal_uInt16 >(2)
|
|
#define MAXNUM_SUGGESTIONS 50
|
|
|
|
|
|
namespace svx
|
|
{
|
|
|
|
using namespace ::com::sun::star;
|
|
using namespace css::uno;
|
|
using namespace css::linguistic2;
|
|
using namespace css::lang;
|
|
using namespace css::container;
|
|
|
|
|
|
namespace
|
|
{
|
|
class FontSwitch
|
|
{
|
|
private:
|
|
OutputDevice& m_rDev;
|
|
|
|
public:
|
|
FontSwitch( OutputDevice& _rDev, const vcl::Font& _rTemporaryFont )
|
|
:m_rDev( _rDev )
|
|
{
|
|
m_rDev.Push( vcl::PushFlags::FONT );
|
|
m_rDev.SetFont( _rTemporaryFont );
|
|
}
|
|
~FontSwitch() COVERITY_NOEXCEPT_FALSE
|
|
{
|
|
m_rDev.Pop();
|
|
}
|
|
};
|
|
|
|
/** a class which allows to draw two texts in a pseudo-ruby way (which basically
|
|
means one text above or below the other, and a little bit smaller)
|
|
*/
|
|
class PseudoRubyText
|
|
{
|
|
public:
|
|
enum RubyPosition
|
|
{
|
|
eAbove, eBelow
|
|
};
|
|
|
|
protected:
|
|
OUString m_sPrimaryText;
|
|
OUString m_sSecondaryText;
|
|
RubyPosition m_ePosition;
|
|
|
|
public:
|
|
PseudoRubyText();
|
|
void init( const OUString& rPrimaryText, const OUString& rSecondaryText, const RubyPosition& rPosition );
|
|
const OUString& getPrimaryText() const { return m_sPrimaryText; }
|
|
const OUString& getSecondaryText() const { return m_sSecondaryText; }
|
|
|
|
public:
|
|
void Paint( vcl::RenderContext& _rDevice, const ::tools::Rectangle& _rRect,
|
|
::tools::Rectangle* _pPrimaryLocation, ::tools::Rectangle* _pSecondaryLocation );
|
|
};
|
|
|
|
}
|
|
|
|
PseudoRubyText::PseudoRubyText()
|
|
: m_ePosition(eAbove)
|
|
{
|
|
}
|
|
|
|
void PseudoRubyText::init( const OUString& rPrimaryText, const OUString& rSecondaryText, const RubyPosition& rPosition )
|
|
{
|
|
m_sPrimaryText = rPrimaryText;
|
|
m_sSecondaryText = rSecondaryText;
|
|
m_ePosition = rPosition;
|
|
}
|
|
|
|
|
|
void PseudoRubyText::Paint(vcl::RenderContext& rRenderContext, const ::tools::Rectangle& _rRect,
|
|
::tools::Rectangle* _pPrimaryLocation, ::tools::Rectangle* _pSecondaryLocation )
|
|
{
|
|
// calculate the text flags for the painting
|
|
constexpr DrawTextFlags nTextStyle = DrawTextFlags::Mnemonic |
|
|
DrawTextFlags::Left |
|
|
DrawTextFlags::VCenter;
|
|
|
|
Size aPlaygroundSize(_rRect.GetSize());
|
|
|
|
// the font for the secondary text:
|
|
vcl::Font aSmallerFont(rRenderContext.GetFont());
|
|
// heuristic: 80% of the original size
|
|
aSmallerFont.SetFontHeight( static_cast<tools::Long>( 0.8 * aSmallerFont.GetFontHeight() ) );
|
|
|
|
// let's calculate the size of our two texts
|
|
::tools::Rectangle aPrimaryRect = rRenderContext.GetTextRect( _rRect, m_sPrimaryText, nTextStyle );
|
|
::tools::Rectangle aSecondaryRect;
|
|
{
|
|
FontSwitch aFontRestore(rRenderContext, aSmallerFont);
|
|
aSecondaryRect = rRenderContext.GetTextRect(_rRect, m_sSecondaryText, nTextStyle);
|
|
}
|
|
|
|
// position these rectangles properly
|
|
// x-axis:
|
|
sal_Int32 nCombinedWidth = std::max( aSecondaryRect.GetWidth(), aPrimaryRect.GetWidth() );
|
|
// the rectangle where both texts will reside is as high as possible, and as wide as the
|
|
// widest of both text rects
|
|
aPrimaryRect.SetLeft( _rRect.Left() );
|
|
aSecondaryRect.SetLeft( aPrimaryRect.Left() );
|
|
aPrimaryRect.SetRight( _rRect.Left() + nCombinedWidth );
|
|
aSecondaryRect.SetRight( aPrimaryRect.Right() );
|
|
|
|
// y-axis:
|
|
sal_Int32 nCombinedHeight = aPrimaryRect.GetHeight() + aSecondaryRect.GetHeight();
|
|
// align to the top, for the moment
|
|
aPrimaryRect.Move( 0, _rRect.Top() - aPrimaryRect.Top() );
|
|
aSecondaryRect.Move( 0, aPrimaryRect.Top() + aPrimaryRect.GetHeight() - aSecondaryRect.Top() );
|
|
// move the rects to the bottom
|
|
aPrimaryRect.Move( 0, ( aPlaygroundSize.Height() - nCombinedHeight ) / 2 );
|
|
aSecondaryRect.Move( 0, ( aPlaygroundSize.Height() - nCombinedHeight ) / 2 );
|
|
|
|
// 'til here, everything we did assumes that the secondary text is painted _below_ the primary
|
|
// text. If this isn't the case, we need to correct the rectangles
|
|
if (eAbove == m_ePosition)
|
|
{
|
|
sal_Int32 nVertDistance = aSecondaryRect.Top() - aPrimaryRect.Top();
|
|
aSecondaryRect.Move( 0, -nVertDistance );
|
|
aPrimaryRect.Move( 0, nCombinedHeight - nVertDistance );
|
|
}
|
|
|
|
// now draw the texts
|
|
// as we already calculated the precise rectangles for the texts, we don't want to
|
|
// use the alignment flags given - within its rect, every text is centered
|
|
DrawTextFlags nDrawTextStyle( nTextStyle );
|
|
nDrawTextStyle &= ~DrawTextFlags( DrawTextFlags::Right | DrawTextFlags::Left | DrawTextFlags::Bottom | DrawTextFlags::Top );
|
|
nDrawTextStyle |= DrawTextFlags::Center | DrawTextFlags::VCenter;
|
|
|
|
rRenderContext.DrawText( aPrimaryRect, m_sPrimaryText, nDrawTextStyle );
|
|
{
|
|
FontSwitch aFontRestore(rRenderContext, aSmallerFont);
|
|
rRenderContext.DrawText( aSecondaryRect, m_sSecondaryText, nDrawTextStyle );
|
|
}
|
|
|
|
// outta here
|
|
if (_pPrimaryLocation)
|
|
*_pPrimaryLocation = aPrimaryRect;
|
|
if (_pSecondaryLocation)
|
|
*_pSecondaryLocation = aSecondaryRect;
|
|
}
|
|
|
|
class RubyRadioButton
|
|
{
|
|
public:
|
|
RubyRadioButton(std::unique_ptr<weld::RadioButton> xControl, std::unique_ptr<weld::Image> xImage);
|
|
void init(const OUString& rPrimaryText, const OUString& rSecondaryText, const PseudoRubyText::RubyPosition& rPosition);
|
|
|
|
void set_sensitive(bool sensitive)
|
|
{
|
|
m_xControl->set_sensitive(sensitive);
|
|
m_xImage->set_sensitive(sensitive);
|
|
}
|
|
void set_active(bool active) { m_xControl->set_active(active); }
|
|
bool get_active() const { return m_xControl->get_active(); }
|
|
|
|
void connect_toggled(const Link<weld::Toggleable&, void>& rLink) { m_xControl->connect_toggled(rLink); }
|
|
|
|
private:
|
|
Size GetOptimalSize() const;
|
|
void Paint(vcl::RenderContext& rRenderContext);
|
|
|
|
ScopedVclPtr<VirtualDevice> m_xVirDev;
|
|
std::unique_ptr<weld::RadioButton> m_xControl;
|
|
std::unique_ptr<weld::Image> m_xImage;
|
|
PseudoRubyText m_aRubyText;
|
|
};
|
|
|
|
RubyRadioButton::RubyRadioButton(std::unique_ptr<weld::RadioButton> xControl, std::unique_ptr<weld::Image> xImage)
|
|
: m_xVirDev(xControl->create_virtual_device())
|
|
, m_xControl(std::move(xControl))
|
|
, m_xImage(std::move(xImage))
|
|
{
|
|
// expand the point size of the desired font to the equivalent pixel size
|
|
weld::SetPointFont(*m_xVirDev, m_xControl->get_font());
|
|
}
|
|
|
|
void RubyRadioButton::init( const OUString& rPrimaryText, const OUString& rSecondaryText, const PseudoRubyText::RubyPosition& rPosition )
|
|
{
|
|
m_aRubyText.init(rPrimaryText, rSecondaryText, rPosition);
|
|
|
|
m_xVirDev->SetOutputSizePixel(GetOptimalSize());
|
|
|
|
Paint(*m_xVirDev);
|
|
|
|
m_xImage->set_image(m_xVirDev.get());
|
|
}
|
|
|
|
void RubyRadioButton::Paint(vcl::RenderContext& rRenderContext)
|
|
{
|
|
::tools::Rectangle aOverallRect(Point(0, 0), rRenderContext.GetOutputSizePixel());
|
|
// inflate the rect a little bit (because the VCL radio button does the same)
|
|
::tools::Rectangle aTextRect( aOverallRect );
|
|
aTextRect.AdjustLeft( 1 ); aTextRect.AdjustRight( -1 );
|
|
aTextRect.AdjustTop( 1 ); aTextRect.AdjustBottom( -1 );
|
|
|
|
// paint the ruby text
|
|
::tools::Rectangle aPrimaryTextLocation;
|
|
::tools::Rectangle aSecondaryTextLocation;
|
|
|
|
m_aRubyText.Paint(rRenderContext, aTextRect, &aPrimaryTextLocation, &aSecondaryTextLocation);
|
|
}
|
|
|
|
Size RubyRadioButton::GetOptimalSize() const
|
|
{
|
|
vcl::Font aSmallerFont(m_xVirDev->GetFont());
|
|
aSmallerFont.SetFontHeight( static_cast<tools::Long>( 0.8 * aSmallerFont.GetFontHeight() ) );
|
|
::tools::Rectangle rect( Point(), Size( SAL_MAX_INT32, SAL_MAX_INT32 ) );
|
|
|
|
Size aPrimarySize = m_xVirDev->GetTextRect( rect, m_aRubyText.getPrimaryText() ).GetSize();
|
|
Size aSecondarySize;
|
|
{
|
|
FontSwitch aFontRestore(*m_xVirDev, aSmallerFont);
|
|
aSecondarySize = m_xVirDev->GetTextRect( rect, m_aRubyText.getSecondaryText() ).GetSize();
|
|
}
|
|
|
|
Size minimumSize;
|
|
minimumSize.setHeight( aPrimarySize.Height() + aSecondarySize.Height() + 5 );
|
|
minimumSize.setWidth(std::max(aPrimarySize.Width(), aSecondarySize.Width()) + 5 );
|
|
return minimumSize;
|
|
}
|
|
|
|
SuggestionSet::SuggestionSet(std::unique_ptr<weld::ScrolledWindow> xScrolledWindow)
|
|
: ValueSet(std::move(xScrolledWindow))
|
|
|
|
{
|
|
}
|
|
|
|
void SuggestionSet::UserDraw( const UserDrawEvent& rUDEvt )
|
|
{
|
|
vcl::RenderContext* pDev = rUDEvt.GetRenderContext();
|
|
::tools::Rectangle aRect = rUDEvt.GetRect();
|
|
sal_uInt16 nItemId = rUDEvt.GetItemId();
|
|
|
|
OUString sText = *static_cast< OUString* >( GetItemData( nItemId ) );
|
|
pDev->DrawText( aRect, sText, DrawTextFlags::Center | DrawTextFlags::VCenter );
|
|
}
|
|
|
|
SuggestionDisplay::SuggestionDisplay(weld::Builder& rBuilder)
|
|
: m_bDisplayListBox( true )
|
|
, m_bInSelectionUpdate( false )
|
|
, m_xValueSet(new SuggestionSet(rBuilder.weld_scrolled_window(u"scrollwin"_ustr, true)))
|
|
, m_xValueSetWin(new weld::CustomWeld(rBuilder, u"valueset"_ustr, *m_xValueSet))
|
|
, m_xListBox(rBuilder.weld_tree_view(u"listbox"_ustr))
|
|
{
|
|
m_xValueSet->SetSelectHdl( LINK( this, SuggestionDisplay, SelectSuggestionValueSetHdl ) );
|
|
m_xListBox->connect_changed( LINK( this, SuggestionDisplay, SelectSuggestionListBoxHdl ) );
|
|
|
|
m_xValueSet->SetLineCount( LINE_CNT );
|
|
m_xValueSet->SetStyle( m_xValueSet->GetStyle() | WB_ITEMBORDER | WB_VSCROLL );
|
|
|
|
auto nItemWidth = 2 * m_xListBox->get_pixel_size(u"AU"_ustr).Width();
|
|
m_xValueSet->SetItemWidth( nItemWidth );
|
|
|
|
Size aSize(m_xListBox->get_approximate_digit_width() * 42, m_xListBox->get_text_height() * 5);
|
|
m_xValueSet->set_size_request(aSize.Width(), aSize.Height());
|
|
m_xListBox->set_size_request(aSize.Width(), aSize.Height());
|
|
|
|
implUpdateDisplay();
|
|
}
|
|
|
|
void SuggestionDisplay::implUpdateDisplay()
|
|
{
|
|
m_xListBox->set_visible(m_bDisplayListBox);
|
|
if (!m_bDisplayListBox)
|
|
m_xValueSetWin->show();
|
|
else
|
|
m_xValueSetWin->hide();
|
|
}
|
|
|
|
weld::Widget& SuggestionDisplay::implGetCurrentControl()
|
|
{
|
|
if (m_bDisplayListBox)
|
|
return *m_xListBox;
|
|
return *m_xValueSet->GetDrawingArea();
|
|
}
|
|
|
|
void SuggestionDisplay::DisplayListBox( bool bDisplayListBox )
|
|
{
|
|
if( m_bDisplayListBox == bDisplayListBox )
|
|
return;
|
|
|
|
weld::Widget& rOldControl = implGetCurrentControl();
|
|
bool bHasFocus = rOldControl.has_focus();
|
|
|
|
m_bDisplayListBox = bDisplayListBox;
|
|
|
|
if( bHasFocus )
|
|
{
|
|
weld::Widget& rNewControl = implGetCurrentControl();
|
|
rNewControl.grab_focus();
|
|
}
|
|
|
|
implUpdateDisplay();
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SuggestionDisplay, SelectSuggestionValueSetHdl, ValueSet*, void)
|
|
{
|
|
SelectSuggestionHdl(false);
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SuggestionDisplay, SelectSuggestionListBoxHdl, weld::TreeView&, void)
|
|
{
|
|
SelectSuggestionHdl(true);
|
|
}
|
|
|
|
void SuggestionDisplay::SelectSuggestionHdl(bool bListBox)
|
|
{
|
|
if( m_bInSelectionUpdate )
|
|
return;
|
|
|
|
m_bInSelectionUpdate = true;
|
|
if (bListBox)
|
|
{
|
|
sal_uInt16 nPos = m_xListBox->get_selected_index();
|
|
m_xValueSet->SelectItem( nPos+1 ); //itemid == pos+1 (id 0 has special meaning)
|
|
}
|
|
else
|
|
{
|
|
sal_uInt16 nPos = m_xValueSet->GetSelectedItemId()-1; //itemid == pos+1 (id 0 has special meaning)
|
|
m_xListBox->select(nPos);
|
|
}
|
|
m_bInSelectionUpdate = false;
|
|
m_aSelectLink.Call( *this );
|
|
}
|
|
|
|
void SuggestionDisplay::SetSelectHdl( const Link<SuggestionDisplay&,void>& rLink )
|
|
{
|
|
m_aSelectLink = rLink;
|
|
}
|
|
|
|
void SuggestionDisplay::Clear()
|
|
{
|
|
m_xListBox->clear();
|
|
m_xValueSet->Clear();
|
|
}
|
|
|
|
void SuggestionDisplay::InsertEntry( const OUString& rStr )
|
|
{
|
|
m_xListBox->append_text(rStr);
|
|
sal_uInt16 nItemId = m_xListBox->n_children(); //itemid == pos+1 (id 0 has special meaning)
|
|
m_xValueSet->InsertItem( nItemId );
|
|
OUString* pItemData = new OUString( rStr );
|
|
m_xValueSet->SetItemData( nItemId, pItemData );
|
|
}
|
|
|
|
void SuggestionDisplay::SelectEntryPos( sal_uInt16 nPos )
|
|
{
|
|
m_xListBox->select(nPos);
|
|
m_xValueSet->SelectItem( nPos+1 ); //itemid == pos+1 (id 0 has special meaning)
|
|
}
|
|
|
|
sal_uInt16 SuggestionDisplay::GetEntryCount() const
|
|
{
|
|
return m_xListBox->n_children();
|
|
}
|
|
|
|
OUString SuggestionDisplay::GetEntry( sal_uInt16 nPos ) const
|
|
{
|
|
return m_xListBox->get_text( nPos );
|
|
}
|
|
|
|
OUString SuggestionDisplay::GetSelectedEntry() const
|
|
{
|
|
return m_xListBox->get_selected_text();
|
|
}
|
|
|
|
void SuggestionDisplay::SetHelpIds()
|
|
{
|
|
m_xValueSet->SetHelpId(HID_HANGULDLG_SUGGESTIONS_GRID);
|
|
m_xListBox->set_help_id(HID_HANGULDLG_SUGGESTIONS_LIST);
|
|
}
|
|
|
|
HangulHanjaConversionDialog::HangulHanjaConversionDialog(weld::Widget* pParent)
|
|
: GenericDialogController(pParent, u"cui/ui/hangulhanjaconversiondialog.ui"_ustr, u"HangulHanjaConversionDialog"_ustr)
|
|
, m_bDocumentMode( true )
|
|
, m_xFind(m_xBuilder->weld_button(u"find"_ustr))
|
|
, m_xIgnore(m_xBuilder->weld_button(u"ignore"_ustr))
|
|
, m_xIgnoreAll(m_xBuilder->weld_button(u"ignoreall"_ustr))
|
|
, m_xReplace(m_xBuilder->weld_button(u"replace"_ustr))
|
|
, m_xReplaceAll(m_xBuilder->weld_button(u"replaceall"_ustr))
|
|
, m_xOptions(m_xBuilder->weld_button(u"options"_ustr))
|
|
, m_xSuggestions(new SuggestionDisplay(*m_xBuilder))
|
|
, m_xSimpleConversion(m_xBuilder->weld_radio_button(u"simpleconversion"_ustr))
|
|
, m_xHangulBracketed(m_xBuilder->weld_radio_button(u"hangulbracket"_ustr))
|
|
, m_xHanjaBracketed(m_xBuilder->weld_radio_button(u"hanjabracket"_ustr))
|
|
, m_xWordInput(m_xBuilder->weld_entry(u"wordinput"_ustr))
|
|
, m_xOriginalWord(m_xBuilder->weld_label(u"originalword"_ustr))
|
|
, m_xHanjaAbove(new RubyRadioButton(m_xBuilder->weld_radio_button(u"hanja_above"_ustr),
|
|
m_xBuilder->weld_image(u"hanja_above_img"_ustr)))
|
|
, m_xHanjaBelow(new RubyRadioButton(m_xBuilder->weld_radio_button(u"hanja_below"_ustr),
|
|
m_xBuilder->weld_image(u"hanja_below_img"_ustr)))
|
|
, m_xHangulAbove(new RubyRadioButton(m_xBuilder->weld_radio_button(u"hangul_above"_ustr),
|
|
m_xBuilder->weld_image(u"hangul_above_img"_ustr)))
|
|
, m_xHangulBelow(new RubyRadioButton(m_xBuilder->weld_radio_button(u"hangul_below"_ustr),
|
|
m_xBuilder->weld_image(u"hangul_below_img"_ustr)))
|
|
, m_xHangulOnly(m_xBuilder->weld_check_button(u"hangulonly"_ustr))
|
|
, m_xHanjaOnly(m_xBuilder->weld_check_button(u"hanjaonly"_ustr))
|
|
, m_xReplaceByChar(m_xBuilder->weld_check_button(u"replacebychar"_ustr))
|
|
{
|
|
m_xSuggestions->set_size_request(m_xOriginalWord->get_approximate_digit_width() * 42,
|
|
m_xOriginalWord->get_text_height() * 5);
|
|
|
|
const OUString sHangul(CuiResId(RID_CUISTR_HANGUL));
|
|
const OUString sHanja(CuiResId(RID_CUISTR_HANJA));
|
|
m_xHanjaAbove->init( sHangul, sHanja, PseudoRubyText::eAbove );
|
|
m_xHanjaBelow->init( sHangul, sHanja, PseudoRubyText::eBelow );
|
|
m_xHangulAbove->init( sHanja, sHangul, PseudoRubyText::eAbove );
|
|
m_xHangulBelow->init( sHanja, sHangul, PseudoRubyText::eBelow );
|
|
|
|
m_xWordInput->connect_changed( LINK( this, HangulHanjaConversionDialog, OnSuggestionModified ) );
|
|
m_xSuggestions->SetSelectHdl( LINK( this, HangulHanjaConversionDialog, OnSuggestionSelected ) );
|
|
m_xReplaceByChar->connect_toggled( LINK( this, HangulHanjaConversionDialog, ClickByCharacterHdl ) );
|
|
m_xHangulOnly->connect_toggled( LINK( this, HangulHanjaConversionDialog, OnConversionDirectionClicked ) );
|
|
m_xHanjaOnly->connect_toggled( LINK( this, HangulHanjaConversionDialog, OnConversionDirectionClicked ) );
|
|
m_xOptions->connect_clicked(LINK(this, HangulHanjaConversionDialog, OnOption));
|
|
|
|
// initial focus
|
|
FocusSuggestion( );
|
|
|
|
// initial control values
|
|
m_xSimpleConversion->set_active(true);
|
|
|
|
m_xSuggestions->SetHelpIds();
|
|
}
|
|
|
|
HangulHanjaConversionDialog::~HangulHanjaConversionDialog()
|
|
{
|
|
}
|
|
|
|
void HangulHanjaConversionDialog::FillSuggestions( const css::uno::Sequence< OUString >& _rSuggestions )
|
|
{
|
|
m_xSuggestions->Clear();
|
|
for ( auto const & suggestion : _rSuggestions )
|
|
m_xSuggestions->InsertEntry( suggestion );
|
|
|
|
// select the first suggestion, and fill in the suggestion edit field
|
|
OUString sFirstSuggestion;
|
|
if ( m_xSuggestions->GetEntryCount() )
|
|
{
|
|
sFirstSuggestion = m_xSuggestions->GetEntry( 0 );
|
|
m_xSuggestions->SelectEntryPos( 0 );
|
|
}
|
|
m_xWordInput->set_text( sFirstSuggestion );
|
|
m_xWordInput->save_value();
|
|
OnSuggestionModified( *m_xWordInput );
|
|
}
|
|
|
|
void HangulHanjaConversionDialog::SetOptionsChangedHdl(const Link<LinkParamNone*,void>& rHdl)
|
|
{
|
|
m_aOptionsChangedLink = rHdl;
|
|
}
|
|
|
|
void HangulHanjaConversionDialog::SetIgnoreHdl(const Link<weld::Button&,void>& rHdl)
|
|
{
|
|
m_xIgnore->connect_clicked(rHdl);
|
|
}
|
|
|
|
void HangulHanjaConversionDialog::SetIgnoreAllHdl(const Link<weld::Button&,void>& rHdl)
|
|
{
|
|
m_xIgnoreAll->connect_clicked(rHdl);
|
|
}
|
|
|
|
void HangulHanjaConversionDialog::SetChangeHdl(const Link<weld::Button&,void>& rHdl )
|
|
{
|
|
m_xReplace->connect_clicked(rHdl);
|
|
}
|
|
|
|
void HangulHanjaConversionDialog::SetChangeAllHdl(const Link<weld::Button&,void>& rHdl)
|
|
{
|
|
m_xReplaceAll->connect_clicked(rHdl);
|
|
}
|
|
|
|
void HangulHanjaConversionDialog::SetFindHdl(const Link<weld::Button&,void>& rHdl)
|
|
{
|
|
m_xFind->connect_clicked(rHdl);
|
|
}
|
|
|
|
void HangulHanjaConversionDialog::SetConversionFormatChangedHdl( const Link<weld::Toggleable&,void>& rHdl )
|
|
{
|
|
m_xSimpleConversion->connect_toggled( rHdl );
|
|
m_xHangulBracketed->connect_toggled( rHdl );
|
|
m_xHanjaBracketed->connect_toggled( rHdl );
|
|
m_xHanjaAbove->connect_toggled( rHdl );
|
|
m_xHanjaBelow->connect_toggled( rHdl );
|
|
m_xHangulAbove->connect_toggled( rHdl );
|
|
m_xHangulBelow->connect_toggled( rHdl );
|
|
}
|
|
|
|
void HangulHanjaConversionDialog::SetClickByCharacterHdl( const Link<weld::Toggleable&,void>& _rHdl )
|
|
{
|
|
m_aClickByCharacterLink = _rHdl;
|
|
}
|
|
|
|
IMPL_LINK_NOARG( HangulHanjaConversionDialog, OnSuggestionSelected, SuggestionDisplay&, void )
|
|
{
|
|
m_xWordInput->set_text(m_xSuggestions->GetSelectedEntry());
|
|
OnSuggestionModified( *m_xWordInput );
|
|
}
|
|
|
|
IMPL_LINK_NOARG( HangulHanjaConversionDialog, OnSuggestionModified, weld::Entry&, void )
|
|
{
|
|
m_xFind->set_sensitive(m_xWordInput->get_value_changed_from_saved());
|
|
|
|
bool bSameLen = m_xWordInput->get_text().getLength() == m_xOriginalWord->get_label().getLength();
|
|
m_xReplace->set_sensitive( m_bDocumentMode && bSameLen );
|
|
m_xReplaceAll->set_sensitive( m_bDocumentMode && bSameLen );
|
|
}
|
|
|
|
IMPL_LINK(HangulHanjaConversionDialog, ClickByCharacterHdl, weld::Toggleable&, rBox, void)
|
|
{
|
|
m_aClickByCharacterLink.Call(rBox);
|
|
bool bByCharacter = rBox.get_active();
|
|
m_xSuggestions->DisplayListBox( !bByCharacter );
|
|
}
|
|
|
|
IMPL_LINK(HangulHanjaConversionDialog, OnConversionDirectionClicked, weld::Toggleable&, rBox, void)
|
|
{
|
|
weld::CheckButton* pOtherBox = nullptr;
|
|
if (&rBox == m_xHangulOnly.get())
|
|
pOtherBox = m_xHanjaOnly.get();
|
|
else
|
|
pOtherBox = m_xHangulOnly.get();
|
|
bool bBoxChecked = rBox.get_active();
|
|
if (bBoxChecked)
|
|
pOtherBox->set_active(false);
|
|
pOtherBox->set_sensitive(!bBoxChecked);
|
|
}
|
|
|
|
IMPL_LINK_NOARG(HangulHanjaConversionDialog, OnOption, weld::Button&, void)
|
|
{
|
|
HangulHanjaOptionsDialog aOptDlg(m_xDialog.get());
|
|
aOptDlg.run();
|
|
m_aOptionsChangedLink.Call( nullptr );
|
|
}
|
|
|
|
OUString HangulHanjaConversionDialog::GetCurrentString( ) const
|
|
{
|
|
return m_xOriginalWord->get_label();
|
|
}
|
|
|
|
void HangulHanjaConversionDialog::FocusSuggestion( )
|
|
{
|
|
m_xWordInput->grab_focus();
|
|
}
|
|
|
|
void HangulHanjaConversionDialog::SetCurrentString( const OUString& _rNewString,
|
|
const Sequence< OUString >& _rSuggestions, bool _bOriginatesFromDocument )
|
|
{
|
|
m_xOriginalWord->set_label(_rNewString);
|
|
|
|
bool bOldDocumentMode = m_bDocumentMode;
|
|
m_bDocumentMode = _bOriginatesFromDocument; // before FillSuggestions!
|
|
FillSuggestions( _rSuggestions );
|
|
|
|
m_xIgnoreAll->set_sensitive( m_bDocumentMode );
|
|
|
|
// switch the def button depending if we're working for document text
|
|
if (bOldDocumentMode == m_bDocumentMode)
|
|
return;
|
|
|
|
weld::Widget* pOldDefButton = nullptr;
|
|
weld::Widget* pNewDefButton = nullptr;
|
|
if (m_bDocumentMode)
|
|
{
|
|
pOldDefButton = m_xFind.get();
|
|
pNewDefButton = m_xReplace.get();
|
|
}
|
|
else
|
|
{
|
|
pOldDefButton = m_xReplace.get();
|
|
pNewDefButton = m_xFind.get();
|
|
}
|
|
|
|
m_xDialog->change_default_widget(pOldDefButton, pNewDefButton);
|
|
}
|
|
|
|
OUString HangulHanjaConversionDialog::GetCurrentSuggestion( ) const
|
|
{
|
|
return m_xWordInput->get_text();
|
|
}
|
|
|
|
void HangulHanjaConversionDialog::SetByCharacter( bool _bByCharacter )
|
|
{
|
|
m_xReplaceByChar->set_active( _bByCharacter );
|
|
m_xSuggestions->DisplayListBox( !_bByCharacter );
|
|
}
|
|
|
|
void HangulHanjaConversionDialog::SetConversionDirectionState(
|
|
bool _bTryBothDirections,
|
|
HHC::ConversionDirection ePrimaryConversionDirection )
|
|
{
|
|
// default state: try both direction
|
|
m_xHangulOnly->set_active( false );
|
|
m_xHangulOnly->set_sensitive(true);
|
|
m_xHanjaOnly->set_active( false );
|
|
m_xHanjaOnly->set_sensitive(true);
|
|
|
|
if (!_bTryBothDirections)
|
|
{
|
|
weld::CheckButton* pBox = ePrimaryConversionDirection == HHC::eHangulToHanja ?
|
|
m_xHangulOnly.get() : m_xHanjaOnly.get();
|
|
pBox->set_active(true);
|
|
OnConversionDirectionClicked(*pBox);
|
|
}
|
|
}
|
|
|
|
bool HangulHanjaConversionDialog::GetUseBothDirections( ) const
|
|
{
|
|
return !m_xHangulOnly->get_active() && !m_xHanjaOnly->get_active();
|
|
}
|
|
|
|
HHC::ConversionDirection HangulHanjaConversionDialog::GetDirection(
|
|
HHC::ConversionDirection eDefaultDirection ) const
|
|
{
|
|
HHC::ConversionDirection eDirection = eDefaultDirection;
|
|
if (m_xHangulOnly->get_active() && !m_xHanjaOnly->get_active())
|
|
eDirection = HHC::eHangulToHanja;
|
|
else if (!m_xHangulOnly->get_active() && m_xHanjaOnly->get_active())
|
|
eDirection = HHC::eHanjaToHangul;
|
|
return eDirection;
|
|
}
|
|
|
|
void HangulHanjaConversionDialog::SetConversionFormat( HHC::ConversionFormat _eType )
|
|
{
|
|
switch ( _eType )
|
|
{
|
|
case HHC::eSimpleConversion: m_xSimpleConversion->set_active(true); break;
|
|
case HHC::eHangulBracketed: m_xHangulBracketed->set_active(true); break;
|
|
case HHC::eHanjaBracketed: m_xHanjaBracketed->set_active(true); break;
|
|
case HHC::eRubyHanjaAbove: m_xHanjaAbove->set_active(true); break;
|
|
case HHC::eRubyHanjaBelow: m_xHanjaBelow->set_active(true); break;
|
|
case HHC::eRubyHangulAbove: m_xHangulAbove->set_active(true); break;
|
|
case HHC::eRubyHangulBelow: m_xHangulBelow->set_active(true); break;
|
|
default:
|
|
OSL_FAIL( "HangulHanjaConversionDialog::SetConversionFormat: unknown type!" );
|
|
}
|
|
}
|
|
|
|
HHC::ConversionFormat HangulHanjaConversionDialog::GetConversionFormat( ) const
|
|
{
|
|
if ( m_xSimpleConversion->get_active() )
|
|
return HHC::eSimpleConversion;
|
|
if ( m_xHangulBracketed->get_active() )
|
|
return HHC::eHangulBracketed;
|
|
if ( m_xHanjaBracketed->get_active() )
|
|
return HHC::eHanjaBracketed;
|
|
if ( m_xHanjaAbove->get_active() )
|
|
return HHC::eRubyHanjaAbove;
|
|
if ( m_xHanjaBelow->get_active() )
|
|
return HHC::eRubyHanjaBelow;
|
|
if ( m_xHangulAbove->get_active() )
|
|
return HHC::eRubyHangulAbove;
|
|
if ( m_xHangulBelow->get_active() )
|
|
return HHC::eRubyHangulBelow;
|
|
|
|
OSL_FAIL( "HangulHanjaConversionDialog::GetConversionFormat: no radio checked?" );
|
|
return HHC::eSimpleConversion;
|
|
}
|
|
|
|
void HangulHanjaConversionDialog::EnableRubySupport( bool bVal )
|
|
{
|
|
m_xHanjaAbove->set_sensitive( bVal );
|
|
m_xHanjaBelow->set_sensitive( bVal );
|
|
m_xHangulAbove->set_sensitive( bVal );
|
|
m_xHangulBelow->set_sensitive( bVal );
|
|
}
|
|
|
|
void HangulHanjaOptionsDialog::Init()
|
|
{
|
|
if( !m_xConversionDictionaryList.is() )
|
|
{
|
|
m_xConversionDictionaryList = ConversionDictionaryList::create( ::comphelper::getProcessComponentContext() );
|
|
}
|
|
|
|
m_aDictList.clear();
|
|
m_xDictsLB->clear();
|
|
|
|
Reference< XNameContainer > xNameCont = m_xConversionDictionaryList->getDictionaryContainer();
|
|
if( xNameCont.is() )
|
|
{
|
|
for (auto& name : xNameCont->getElementNames())
|
|
{
|
|
Any aAny(xNameCont->getByName(name));
|
|
Reference< XConversionDictionary > xDic;
|
|
if( ( aAny >>= xDic ) && xDic.is() )
|
|
{
|
|
if( LANGUAGE_KOREAN == LanguageTag( xDic->getLocale() ).getLanguageType() )
|
|
{
|
|
m_aDictList.push_back( xDic );
|
|
AddDict( xDic->getName(), xDic->isActive() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (m_xDictsLB->n_children())
|
|
m_xDictsLB->select(0);
|
|
}
|
|
|
|
IMPL_LINK_NOARG(HangulHanjaOptionsDialog, OkHdl, weld::Button&, void)
|
|
{
|
|
sal_uInt32 nCnt = m_aDictList.size();
|
|
sal_uInt32 n = 0;
|
|
sal_uInt32 nActiveDics = 0;
|
|
Sequence< OUString > aActiveDics;
|
|
|
|
aActiveDics.realloc( nCnt );
|
|
OUString* pActActiveDic = aActiveDics.getArray();
|
|
|
|
while( nCnt )
|
|
{
|
|
Reference< XConversionDictionary > xDict = m_aDictList[ n ];
|
|
|
|
DBG_ASSERT( xDict.is(), "-HangulHanjaOptionsDialog::OkHdl(): someone is evaporated..." );
|
|
|
|
bool bActive = m_xDictsLB->get_toggle(n) == TRISTATE_TRUE;
|
|
xDict->setActive( bActive );
|
|
Reference< util::XFlushable > xFlush( xDict, uno::UNO_QUERY );
|
|
if( xFlush.is() )
|
|
xFlush->flush();
|
|
|
|
if( bActive )
|
|
{
|
|
pActActiveDic[ nActiveDics ] = xDict->getName();
|
|
++nActiveDics;
|
|
}
|
|
|
|
++n;
|
|
--nCnt;
|
|
}
|
|
|
|
// save configuration
|
|
aActiveDics.realloc( nActiveDics );
|
|
Any aTmp;
|
|
SvtLinguConfig aLngCfg;
|
|
aTmp <<= aActiveDics;
|
|
aLngCfg.SetProperty( UPH_ACTIVE_CONVERSION_DICTIONARIES, aTmp );
|
|
|
|
aTmp <<= m_xIgnorepostCB->get_active();
|
|
aLngCfg.SetProperty( UPH_IS_IGNORE_POST_POSITIONAL_WORD, aTmp );
|
|
|
|
aTmp <<= m_xShowrecentlyfirstCB->get_active();
|
|
aLngCfg.SetProperty( UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST, aTmp );
|
|
|
|
aTmp <<= m_xAutoreplaceuniqueCB->get_active();
|
|
aLngCfg.SetProperty( UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES, aTmp );
|
|
|
|
m_xDialog->response(RET_OK);
|
|
}
|
|
|
|
IMPL_LINK_NOARG(HangulHanjaOptionsDialog, DictsLB_SelectHdl, weld::TreeView&, void)
|
|
{
|
|
bool bSel = m_xDictsLB->get_selected_index() != -1;
|
|
|
|
m_xEditPB->set_sensitive(bSel);
|
|
m_xDeletePB->set_sensitive(bSel);
|
|
}
|
|
|
|
IMPL_LINK_NOARG(HangulHanjaOptionsDialog, NewDictHdl, weld::Button&, void)
|
|
{
|
|
OUString aName;
|
|
HangulHanjaNewDictDialog aNewDlg(m_xDialog.get());
|
|
aNewDlg.run();
|
|
if (!aNewDlg.GetName(aName))
|
|
return;
|
|
|
|
if( !m_xConversionDictionaryList.is() )
|
|
return;
|
|
|
|
try
|
|
{
|
|
Reference< XConversionDictionary > xDic =
|
|
m_xConversionDictionaryList->addNewDictionary( aName, LanguageTag::convertToLocale( LANGUAGE_KOREAN ), ConversionDictionaryType::HANGUL_HANJA );
|
|
|
|
if( xDic.is() )
|
|
{
|
|
//adapt local caches:
|
|
m_aDictList.push_back( xDic );
|
|
AddDict( xDic->getName(), xDic->isActive() );
|
|
}
|
|
}
|
|
catch( const ElementExistException& )
|
|
{
|
|
}
|
|
catch( const NoSupportException& )
|
|
{
|
|
}
|
|
}
|
|
|
|
IMPL_LINK_NOARG(HangulHanjaOptionsDialog, EditDictHdl, weld::Button&, void)
|
|
{
|
|
int nEntry = m_xDictsLB->get_selected_index();
|
|
DBG_ASSERT(nEntry != -1, "+HangulHanjaEditDictDialog::EditDictHdl(): call of edit should not be possible with no selection!");
|
|
if (nEntry != -1)
|
|
{
|
|
HangulHanjaEditDictDialog aEdDlg(m_xDialog.get(), m_aDictList, nEntry);
|
|
aEdDlg.run();
|
|
}
|
|
}
|
|
|
|
IMPL_LINK_NOARG(HangulHanjaOptionsDialog, DeleteDictHdl, weld::Button&, void)
|
|
{
|
|
int nSelPos = m_xDictsLB->get_selected_index();
|
|
if (nSelPos == -1)
|
|
return;
|
|
|
|
Reference< XConversionDictionary > xDic( m_aDictList[ nSelPos ] );
|
|
if( !(m_xConversionDictionaryList.is() && xDic.is()) )
|
|
return;
|
|
|
|
Reference< XNameContainer > xNameCont = m_xConversionDictionaryList->getDictionaryContainer();
|
|
if( !xNameCont.is() )
|
|
return;
|
|
|
|
try
|
|
{
|
|
xNameCont->removeByName( xDic->getName() );
|
|
|
|
//adapt local caches:
|
|
m_aDictList.erase(m_aDictList.begin()+nSelPos );
|
|
m_xDictsLB->remove(nSelPos);
|
|
}
|
|
catch( const ElementExistException& )
|
|
{
|
|
}
|
|
catch( const NoSupportException& )
|
|
{
|
|
}
|
|
}
|
|
|
|
HangulHanjaOptionsDialog::HangulHanjaOptionsDialog(weld::Window* pParent)
|
|
: GenericDialogController(pParent, u"cui/ui/hangulhanjaoptdialog.ui"_ustr, u"HangulHanjaOptDialog"_ustr)
|
|
, m_xDictsLB(m_xBuilder->weld_tree_view(u"dicts"_ustr))
|
|
, m_xIgnorepostCB(m_xBuilder->weld_check_button(u"ignorepost"_ustr))
|
|
, m_xShowrecentlyfirstCB(m_xBuilder->weld_check_button(u"showrecentfirst"_ustr))
|
|
, m_xAutoreplaceuniqueCB(m_xBuilder->weld_check_button(u"autoreplaceunique"_ustr))
|
|
, m_xNewPB(m_xBuilder->weld_button(u"new"_ustr))
|
|
, m_xEditPB(m_xBuilder->weld_button(u"edit"_ustr))
|
|
, m_xDeletePB(m_xBuilder->weld_button(u"delete"_ustr))
|
|
, m_xOkPB(m_xBuilder->weld_button(u"ok"_ustr))
|
|
{
|
|
m_xDictsLB->set_size_request(m_xDictsLB->get_approximate_digit_width() * 32,
|
|
m_xDictsLB->get_height_rows(5));
|
|
|
|
m_xDictsLB->enable_toggle_buttons(weld::ColumnToggleType::Check);
|
|
|
|
m_xDictsLB->connect_changed( LINK( this, HangulHanjaOptionsDialog, DictsLB_SelectHdl ) );
|
|
|
|
m_xOkPB->connect_clicked( LINK( this, HangulHanjaOptionsDialog, OkHdl ) );
|
|
m_xNewPB->connect_clicked( LINK( this, HangulHanjaOptionsDialog, NewDictHdl ) );
|
|
m_xEditPB->connect_clicked( LINK( this, HangulHanjaOptionsDialog, EditDictHdl ) );
|
|
m_xDeletePB->connect_clicked( LINK( this, HangulHanjaOptionsDialog, DeleteDictHdl ) );
|
|
|
|
SvtLinguConfig aLngCfg;
|
|
Any aTmp;
|
|
bool bVal = bool();
|
|
aTmp = aLngCfg.GetProperty( UPH_IS_IGNORE_POST_POSITIONAL_WORD );
|
|
if( aTmp >>= bVal )
|
|
m_xIgnorepostCB->set_active( bVal );
|
|
|
|
aTmp = aLngCfg.GetProperty( UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST );
|
|
if( aTmp >>= bVal )
|
|
m_xShowrecentlyfirstCB->set_active( bVal );
|
|
|
|
aTmp = aLngCfg.GetProperty( UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES );
|
|
if( aTmp >>= bVal )
|
|
m_xAutoreplaceuniqueCB->set_active( bVal );
|
|
|
|
Init();
|
|
}
|
|
|
|
HangulHanjaOptionsDialog::~HangulHanjaOptionsDialog()
|
|
{
|
|
}
|
|
|
|
void HangulHanjaOptionsDialog::AddDict(const OUString& rName, bool bChecked)
|
|
{
|
|
m_xDictsLB->append();
|
|
int nRow = m_xDictsLB->n_children() - 1;
|
|
m_xDictsLB->set_toggle(nRow, bChecked ? TRISTATE_TRUE : TRISTATE_FALSE);
|
|
m_xDictsLB->set_text(nRow, rName, 0);
|
|
m_xDictsLB->set_id(nRow, rName);
|
|
}
|
|
|
|
IMPL_LINK_NOARG(HangulHanjaNewDictDialog, OKHdl, weld::Button&, void)
|
|
{
|
|
OUString aName(comphelper::string::stripEnd(m_xDictNameED->get_text(), ' '));
|
|
|
|
m_bEntered = !aName.isEmpty();
|
|
if (m_bEntered)
|
|
m_xDictNameED->set_text(aName); // do this in case of trailing chars have been deleted
|
|
|
|
m_xDialog->response(RET_OK);
|
|
}
|
|
|
|
IMPL_LINK_NOARG(HangulHanjaNewDictDialog, ModifyHdl, weld::Entry&, void)
|
|
{
|
|
OUString aName(comphelper::string::stripEnd(m_xDictNameED->get_text(), ' '));
|
|
|
|
m_xOkBtn->set_sensitive(!aName.isEmpty());
|
|
}
|
|
|
|
HangulHanjaNewDictDialog::HangulHanjaNewDictDialog(weld::Window* pParent)
|
|
: GenericDialogController(pParent, u"cui/ui/hangulhanjaadddialog.ui"_ustr, u"HangulHanjaAddDialog"_ustr)
|
|
, m_bEntered(false)
|
|
, m_xOkBtn(m_xBuilder->weld_button(u"ok"_ustr))
|
|
, m_xDictNameED(m_xBuilder->weld_entry(u"entry"_ustr))
|
|
{
|
|
m_xOkBtn->connect_clicked( LINK( this, HangulHanjaNewDictDialog, OKHdl ) );
|
|
m_xDictNameED->connect_changed( LINK( this, HangulHanjaNewDictDialog, ModifyHdl ) );
|
|
}
|
|
|
|
HangulHanjaNewDictDialog::~HangulHanjaNewDictDialog()
|
|
{
|
|
}
|
|
|
|
bool HangulHanjaNewDictDialog::GetName( OUString& _rRetName ) const
|
|
{
|
|
if( m_bEntered )
|
|
_rRetName = comphelper::string::stripEnd(m_xDictNameED->get_text(), ' ');
|
|
|
|
return m_bEntered;
|
|
}
|
|
|
|
class SuggestionList
|
|
{
|
|
private:
|
|
protected:
|
|
std::vector<OUString> m_vElements;
|
|
sal_uInt16 m_nNumOfEntries;
|
|
// index of the internal iterator, used for First() and Next() methods
|
|
sal_uInt16 m_nAct;
|
|
|
|
const OUString* Next_();
|
|
public:
|
|
SuggestionList();
|
|
~SuggestionList();
|
|
|
|
void Set( const OUString& _rElement, sal_uInt16 _nNumOfElement );
|
|
void Reset( sal_uInt16 _nNumOfElement );
|
|
const OUString & Get( sal_uInt16 _nNumOfElement ) const;
|
|
void Clear();
|
|
|
|
const OUString* First();
|
|
const OUString* Next();
|
|
|
|
sal_uInt16 GetCount() const { return m_nNumOfEntries; }
|
|
};
|
|
|
|
SuggestionList::SuggestionList() :
|
|
m_vElements(MAXNUM_SUGGESTIONS)
|
|
{
|
|
m_nAct = m_nNumOfEntries = 0;
|
|
}
|
|
|
|
SuggestionList::~SuggestionList()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
void SuggestionList::Set( const OUString& _rElement, sal_uInt16 _nNumOfElement )
|
|
{
|
|
m_vElements[_nNumOfElement] = _rElement;
|
|
++m_nNumOfEntries;
|
|
}
|
|
|
|
void SuggestionList::Reset( sal_uInt16 _nNumOfElement )
|
|
{
|
|
m_vElements[_nNumOfElement].clear();
|
|
--m_nNumOfEntries;
|
|
}
|
|
|
|
const OUString& SuggestionList::Get( sal_uInt16 _nNumOfElement ) const
|
|
{
|
|
return m_vElements[_nNumOfElement];
|
|
}
|
|
|
|
void SuggestionList::Clear()
|
|
{
|
|
if( m_nNumOfEntries )
|
|
{
|
|
for (auto & vElement : m_vElements)
|
|
vElement.clear();
|
|
m_nNumOfEntries = m_nAct = 0;
|
|
}
|
|
}
|
|
|
|
const OUString* SuggestionList::Next_()
|
|
{
|
|
while( m_nAct < m_vElements.size() )
|
|
{
|
|
auto & s = m_vElements[ m_nAct ];
|
|
if (!s.isEmpty())
|
|
return &s;
|
|
++m_nAct;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
const OUString* SuggestionList::First()
|
|
{
|
|
m_nAct = 0;
|
|
return Next_();
|
|
}
|
|
|
|
const OUString* SuggestionList::Next()
|
|
{
|
|
const OUString* pRet;
|
|
|
|
if( m_nAct < m_nNumOfEntries )
|
|
{
|
|
++m_nAct;
|
|
pRet = Next_();
|
|
}
|
|
else
|
|
pRet = nullptr;
|
|
|
|
return pRet;
|
|
}
|
|
|
|
|
|
bool SuggestionEdit::ShouldScroll( bool _bUp ) const
|
|
{
|
|
bool bRet = false;
|
|
|
|
if( _bUp )
|
|
{
|
|
if( !m_pPrev )
|
|
bRet = m_pScrollBar->vadjustment_get_value() > m_pScrollBar->vadjustment_get_lower();
|
|
}
|
|
else
|
|
{
|
|
if( !m_pNext )
|
|
bRet = m_pScrollBar->vadjustment_get_value() < ( m_pScrollBar->vadjustment_get_upper() - 4 );
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
void SuggestionEdit::DoJump( bool _bUp )
|
|
{
|
|
m_pScrollBar->vadjustment_set_value( m_pScrollBar->vadjustment_get_value() + ( _bUp? -1 : 1 ) );
|
|
m_pParent->UpdateScrollbar();
|
|
}
|
|
|
|
SuggestionEdit::SuggestionEdit(std::unique_ptr<weld::Entry> xEntry, HangulHanjaEditDictDialog* pParent)
|
|
: m_pParent(pParent)
|
|
, m_pPrev(nullptr)
|
|
, m_pNext(nullptr)
|
|
, m_pScrollBar(nullptr)
|
|
, m_xEntry(std::move(xEntry))
|
|
{
|
|
m_xEntry->connect_key_press(LINK(this, SuggestionEdit, KeyInputHdl));
|
|
}
|
|
|
|
IMPL_LINK(SuggestionEdit, KeyInputHdl, const KeyEvent&, rKEvt, bool)
|
|
{
|
|
bool bHandled = false;
|
|
|
|
const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
|
|
sal_uInt16 nMod = rKeyCode.GetModifier();
|
|
sal_uInt16 nCode = rKeyCode.GetCode();
|
|
if( nCode == KEY_TAB && ( !nMod || KEY_SHIFT == nMod ) )
|
|
{
|
|
bool bUp = KEY_SHIFT == nMod;
|
|
if( ShouldScroll( bUp ) )
|
|
{
|
|
DoJump( bUp );
|
|
m_xEntry->select_region(0, -1);
|
|
// Tab-travel doesn't really happen, so emulate it by setting a selection manually
|
|
bHandled = true;
|
|
}
|
|
}
|
|
else if( KEY_UP == nCode || KEY_DOWN == nCode )
|
|
{
|
|
bool bUp = KEY_UP == nCode;
|
|
if( ShouldScroll( bUp ) )
|
|
{
|
|
DoJump( bUp );
|
|
bHandled = true;
|
|
}
|
|
else if( bUp )
|
|
{
|
|
if( m_pPrev )
|
|
{
|
|
m_pPrev->grab_focus();
|
|
bHandled = true;
|
|
}
|
|
}
|
|
else if( m_pNext )
|
|
{
|
|
m_pNext->grab_focus();
|
|
bHandled = true;
|
|
}
|
|
}
|
|
|
|
return bHandled;
|
|
}
|
|
|
|
void SuggestionEdit::init(weld::ScrolledWindow* pScrollBar, SuggestionEdit* pPrev, SuggestionEdit* pNext)
|
|
{
|
|
m_pScrollBar = pScrollBar;
|
|
m_pPrev = pPrev;
|
|
m_pNext = pNext;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
bool GetConversions( const Reference< XConversionDictionary >& _xDict,
|
|
const OUString& _rOrg,
|
|
Sequence< OUString >& _rEntries )
|
|
{
|
|
bool bRet = false;
|
|
if( _xDict.is() && !_rOrg.isEmpty() )
|
|
{
|
|
try
|
|
{
|
|
_rEntries = _xDict->getConversions( _rOrg,
|
|
0,
|
|
_rOrg.getLength(),
|
|
ConversionDirection_FROM_LEFT,
|
|
css::i18n::TextConversionOption::NONE );
|
|
bRet = _rEntries.hasElements();
|
|
}
|
|
catch( const IllegalArgumentException& )
|
|
{
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
}
|
|
|
|
IMPL_LINK_NOARG( HangulHanjaEditDictDialog, ScrollHdl, weld::ScrolledWindow&, void )
|
|
{
|
|
UpdateScrollbar();
|
|
}
|
|
|
|
IMPL_LINK_NOARG( HangulHanjaEditDictDialog, OriginalModifyHdl, weld::ComboBox&, void )
|
|
{
|
|
m_bModifiedOriginal = true;
|
|
m_aOriginal = comphelper::string::stripEnd( m_xOriginalLB->get_active_text(), ' ' );
|
|
|
|
UpdateSuggestions();
|
|
UpdateButtonStates();
|
|
}
|
|
|
|
IMPL_LINK( HangulHanjaEditDictDialog, EditModifyHdl1, weld::Entry&, rEdit, void )
|
|
{
|
|
EditModify( &rEdit, 0 );
|
|
}
|
|
|
|
IMPL_LINK( HangulHanjaEditDictDialog, EditModifyHdl2, weld::Entry&, rEdit, void )
|
|
{
|
|
EditModify( &rEdit, 1 );
|
|
}
|
|
|
|
IMPL_LINK( HangulHanjaEditDictDialog, EditModifyHdl3, weld::Entry&, rEdit, void )
|
|
{
|
|
EditModify( &rEdit, 2 );
|
|
}
|
|
|
|
IMPL_LINK( HangulHanjaEditDictDialog, EditModifyHdl4, weld::Entry&, rEdit, void )
|
|
{
|
|
EditModify( &rEdit, 3 );
|
|
}
|
|
|
|
IMPL_LINK_NOARG( HangulHanjaEditDictDialog, BookLBSelectHdl, weld::ComboBox&, void )
|
|
{
|
|
InitEditDictDialog( m_xBookLB->get_active() );
|
|
}
|
|
|
|
IMPL_LINK_NOARG( HangulHanjaEditDictDialog, NewPBPushHdl, weld::Button&, void )
|
|
{
|
|
DBG_ASSERT( m_xSuggestions, "-HangulHanjaEditDictDialog::NewPBPushHdl(): no suggestions... search in hell..." );
|
|
Reference< XConversionDictionary > xDict = m_rDictList[ m_nCurrentDict ];
|
|
if( xDict.is() && m_xSuggestions )
|
|
{
|
|
//delete old entry
|
|
bool bRemovedSomething = DeleteEntryFromDictionary( xDict );
|
|
|
|
OUString aLeft( m_aOriginal );
|
|
const OUString* pRight = m_xSuggestions->First();
|
|
bool bAddedSomething = false;
|
|
while( pRight )
|
|
{
|
|
try
|
|
{
|
|
//add new entry
|
|
xDict->addEntry( aLeft, *pRight );
|
|
bAddedSomething = true;
|
|
}
|
|
catch( const IllegalArgumentException& )
|
|
{
|
|
}
|
|
catch( const ElementExistException& )
|
|
{
|
|
}
|
|
|
|
pRight = m_xSuggestions->Next();
|
|
}
|
|
|
|
if( bAddedSomething || bRemovedSomething )
|
|
InitEditDictDialog( m_nCurrentDict );
|
|
}
|
|
else
|
|
{
|
|
SAL_INFO( "cui.dialogs", "dictionary faded away..." );
|
|
}
|
|
}
|
|
|
|
bool HangulHanjaEditDictDialog::DeleteEntryFromDictionary( const Reference< XConversionDictionary >& xDict )
|
|
{
|
|
bool bRemovedSomething = false;
|
|
if( xDict.is() )
|
|
{
|
|
OUString aOrg( m_aOriginal );
|
|
Sequence< OUString > aEntries;
|
|
GetConversions( xDict, m_aOriginal, aEntries );
|
|
|
|
sal_uInt32 n = aEntries.getLength();
|
|
OUString* pEntry = aEntries.getArray();
|
|
while( n )
|
|
{
|
|
try
|
|
{
|
|
xDict->removeEntry( aOrg, *pEntry );
|
|
bRemovedSomething = true;
|
|
}
|
|
catch( const NoSuchElementException& )
|
|
{ // can not be...
|
|
}
|
|
|
|
++pEntry;
|
|
--n;
|
|
}
|
|
}
|
|
return bRemovedSomething;
|
|
}
|
|
|
|
IMPL_LINK_NOARG( HangulHanjaEditDictDialog, DeletePBPushHdl, weld::Button&, void )
|
|
{
|
|
if( DeleteEntryFromDictionary( m_rDictList[ m_nCurrentDict ] ) )
|
|
{
|
|
m_aOriginal.clear();
|
|
m_bModifiedOriginal = true;
|
|
InitEditDictDialog( m_nCurrentDict );
|
|
}
|
|
}
|
|
|
|
void HangulHanjaEditDictDialog::InitEditDictDialog( sal_uInt32 nSelDict )
|
|
{
|
|
if( m_xSuggestions )
|
|
m_xSuggestions->Clear();
|
|
|
|
if( m_nCurrentDict != nSelDict )
|
|
{
|
|
m_nCurrentDict = nSelDict;
|
|
m_aOriginal.clear();
|
|
m_bModifiedOriginal = true;
|
|
}
|
|
|
|
UpdateOriginalLB();
|
|
|
|
m_xOriginalLB->set_entry_text( !m_aOriginal.isEmpty() ? m_aOriginal : m_aEditHintText);
|
|
m_xOriginalLB->select_entry_region(0, -1);
|
|
m_xOriginalLB->grab_focus();
|
|
|
|
UpdateSuggestions();
|
|
UpdateButtonStates();
|
|
}
|
|
|
|
void HangulHanjaEditDictDialog::UpdateOriginalLB()
|
|
{
|
|
m_xOriginalLB->clear();
|
|
Reference< XConversionDictionary > xDict = m_rDictList[ m_nCurrentDict ];
|
|
if( xDict.is() )
|
|
{
|
|
Sequence< OUString > aEntries = xDict->getConversionEntries( ConversionDirection_FROM_LEFT );
|
|
sal_uInt32 n = aEntries.getLength();
|
|
OUString* pEntry = aEntries.getArray();
|
|
while( n )
|
|
{
|
|
m_xOriginalLB->append_text( *pEntry );
|
|
|
|
++pEntry;
|
|
--n;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SAL_INFO( "cui.dialogs", "dictionary faded away..." );
|
|
}
|
|
}
|
|
|
|
void HangulHanjaEditDictDialog::UpdateButtonStates()
|
|
{
|
|
bool bHaveValidOriginalString = !m_aOriginal.isEmpty() && m_aOriginal != m_aEditHintText;
|
|
bool bNew = bHaveValidOriginalString && m_xSuggestions && m_xSuggestions->GetCount() > 0;
|
|
bNew = bNew && ( m_bModifiedSuggestions || m_bModifiedOriginal );
|
|
|
|
m_xNewPB->set_sensitive( bNew );
|
|
m_xDeletePB->set_sensitive(!m_bModifiedOriginal && bHaveValidOriginalString);
|
|
}
|
|
|
|
void HangulHanjaEditDictDialog::UpdateSuggestions()
|
|
{
|
|
Sequence< OUString > aEntries;
|
|
bool bFound = GetConversions( m_rDictList[ m_nCurrentDict ], m_aOriginal, aEntries );
|
|
if( bFound )
|
|
{
|
|
m_bModifiedOriginal = false;
|
|
|
|
if( m_xSuggestions )
|
|
m_xSuggestions->Clear();
|
|
|
|
//fill found entries into boxes
|
|
if (aEntries.hasElements())
|
|
{
|
|
if( !m_xSuggestions )
|
|
m_xSuggestions.reset(new SuggestionList);
|
|
|
|
for (sal_Int32 n = 0; n < aEntries.getLength(); ++n)
|
|
m_xSuggestions->Set(aEntries[n], n);
|
|
}
|
|
m_bModifiedSuggestions = false;
|
|
}
|
|
|
|
m_xScrollSB->vadjustment_set_value( 0 );
|
|
UpdateScrollbar(); // will force edits to be filled new
|
|
}
|
|
|
|
void HangulHanjaEditDictDialog::SetEditText(SuggestionEdit& rEdit, sal_uInt16 nEntryNum)
|
|
{
|
|
OUString aStr;
|
|
if( m_xSuggestions )
|
|
{
|
|
aStr = m_xSuggestions->Get(nEntryNum);
|
|
}
|
|
|
|
rEdit.set_text(aStr);
|
|
}
|
|
|
|
void HangulHanjaEditDictDialog::EditModify(const weld::Entry* pEdit, sal_uInt8 _nEntryOffset)
|
|
{
|
|
m_bModifiedSuggestions = true;
|
|
|
|
OUString aTxt( pEdit->get_text() );
|
|
sal_uInt16 nEntryNum = m_nTopPos + _nEntryOffset;
|
|
if( aTxt.isEmpty() )
|
|
{
|
|
//reset suggestion
|
|
if( m_xSuggestions )
|
|
m_xSuggestions->Reset( nEntryNum );
|
|
}
|
|
else
|
|
{
|
|
//set suggestion
|
|
if( !m_xSuggestions )
|
|
m_xSuggestions.reset(new SuggestionList);
|
|
m_xSuggestions->Set( aTxt, nEntryNum );
|
|
}
|
|
|
|
UpdateButtonStates();
|
|
}
|
|
|
|
HangulHanjaEditDictDialog::HangulHanjaEditDictDialog(weld::Window* pParent, HHDictList& _rDictList, sal_uInt32 nSelDict)
|
|
: GenericDialogController(pParent, u"cui/ui/hangulhanjaeditdictdialog.ui"_ustr, u"HangulHanjaEditDictDialog"_ustr)
|
|
, m_aEditHintText ( CuiResId(RID_CUISTR_EDITHINT) )
|
|
, m_rDictList ( _rDictList )
|
|
, m_nCurrentDict ( 0xFFFFFFFF )
|
|
, m_nTopPos ( 0 )
|
|
, m_bModifiedSuggestions ( false )
|
|
, m_bModifiedOriginal ( false )
|
|
, m_xBookLB(m_xBuilder->weld_combo_box(u"book"_ustr))
|
|
, m_xOriginalLB(m_xBuilder->weld_combo_box(u"original"_ustr))
|
|
, m_xEdit1(new SuggestionEdit(m_xBuilder->weld_entry(u"edit1"_ustr), this))
|
|
, m_xEdit2(new SuggestionEdit(m_xBuilder->weld_entry(u"edit2"_ustr), this))
|
|
, m_xEdit3(new SuggestionEdit(m_xBuilder->weld_entry(u"edit3"_ustr), this))
|
|
, m_xEdit4(new SuggestionEdit(m_xBuilder->weld_entry(u"edit4"_ustr), this))
|
|
, m_xContents(m_xBuilder->weld_widget(u"box"_ustr))
|
|
, m_xScrollSB(m_xBuilder->weld_scrolled_window(u"scrollbar"_ustr, true))
|
|
, m_xNewPB(m_xBuilder->weld_button(u"new"_ustr))
|
|
, m_xDeletePB(m_xBuilder->weld_button(u"delete"_ustr))
|
|
{
|
|
Size aSize(m_xContents->get_preferred_size());
|
|
m_xScrollSB->set_size_request(-1, aSize.Height());
|
|
|
|
m_xEdit1->init( m_xScrollSB.get(), nullptr, m_xEdit2.get() );
|
|
m_xEdit2->init( m_xScrollSB.get(), m_xEdit1.get(), m_xEdit3.get() );
|
|
m_xEdit3->init( m_xScrollSB.get(), m_xEdit2.get(), m_xEdit4.get() );
|
|
m_xEdit4->init( m_xScrollSB.get(), m_xEdit3.get(), nullptr );
|
|
|
|
m_xOriginalLB->connect_changed( LINK( this, HangulHanjaEditDictDialog, OriginalModifyHdl ) );
|
|
|
|
m_xNewPB->connect_clicked( LINK( this, HangulHanjaEditDictDialog, NewPBPushHdl ) );
|
|
m_xNewPB->set_sensitive( false );
|
|
|
|
m_xDeletePB->connect_clicked( LINK( this, HangulHanjaEditDictDialog, DeletePBPushHdl ) );
|
|
m_xDeletePB->set_sensitive( false );
|
|
|
|
static_assert(MAXNUM_SUGGESTIONS >= 5, "number of suggestions should not under-run the value of 5");
|
|
|
|
// 4 here, because we have 4 edits / page
|
|
m_xScrollSB->vadjustment_configure(0, 0, MAXNUM_SUGGESTIONS, 1, 4, 4);
|
|
m_xScrollSB->connect_vadjustment_changed(LINK(this, HangulHanjaEditDictDialog, ScrollHdl));
|
|
|
|
m_xEdit1->connect_changed( LINK( this, HangulHanjaEditDictDialog, EditModifyHdl1 ) );
|
|
m_xEdit2->connect_changed( LINK( this, HangulHanjaEditDictDialog, EditModifyHdl2 ) );
|
|
m_xEdit3->connect_changed( LINK( this, HangulHanjaEditDictDialog, EditModifyHdl3 ) );
|
|
m_xEdit4->connect_changed( LINK( this, HangulHanjaEditDictDialog, EditModifyHdl4 ) );
|
|
|
|
m_xBookLB->connect_changed( LINK( this, HangulHanjaEditDictDialog, BookLBSelectHdl ) );
|
|
sal_uInt32 nDictCnt = m_rDictList.size();
|
|
for( sal_uInt32 n = 0 ; n < nDictCnt ; ++n )
|
|
{
|
|
Reference< XConversionDictionary > xDic( m_rDictList[n] );
|
|
OUString aName;
|
|
if( xDic.is() )
|
|
aName = xDic->getName();
|
|
m_xBookLB->append_text( aName );
|
|
}
|
|
m_xBookLB->set_active(nSelDict);
|
|
|
|
InitEditDictDialog(nSelDict);
|
|
}
|
|
|
|
HangulHanjaEditDictDialog::~HangulHanjaEditDictDialog()
|
|
{
|
|
}
|
|
|
|
void HangulHanjaEditDictDialog::UpdateScrollbar()
|
|
{
|
|
sal_uInt16 nPos = m_xScrollSB->vadjustment_get_value();
|
|
m_nTopPos = nPos;
|
|
|
|
SetEditText( *m_xEdit1, nPos++ );
|
|
SetEditText( *m_xEdit2, nPos++ );
|
|
SetEditText( *m_xEdit3, nPos++ );
|
|
SetEditText( *m_xEdit4, nPos );
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|