Files
libreoffice/vcl/source/window/mnemonic.cxx

398 lines
13 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
re-base on ALv2 code. Includes (at least) relevant parts of: linecap: Reintegrating finished LineCap feature Patch contributed by Regina Henschel http://svn.apache.org/viewvc?view=revision&revision=1232507 Patches contributed by Sven Jacobi impress212: #i81610# fixed animation export http://svn.apache.org/viewvc?view=revision&revision=1167620 impress212: drawinglayer gbuild environment changes http://svn.apache.org/viewvc?view=revision&revision=1167627 http://svn.apache.org/viewvc?view=revision&revision=1167628 impress212: DffPropSet -> minor code improvements, removing table http://svn.apache.org/viewvc?view=revision&revision=1167634 impress212: #158494# fixed excel import (text rotation) http://svn.apache.org/viewvc?view=revision&revision=1167638 Patches contributed by Armin Le Grand Svg: Reintegrated Svg replacement from /branches/alg/svgreplavement http://svn.apache.org/viewvc?view=revision&revision=1220836 #118728# changed indentifying definitions for Svg file detection http://svn.apache.org/viewvc?view=revision&revision=1229961 #118838# LineGeometry creation for complicated cases optimized to create single Polygons http://svn.apache.org/viewvc?view=revision&revision=1236232 #119176# corrected file type detection for SVG for svg files without xml header http://svn.apache.org/viewvc?view=revision&revision=1309445 #118728# Extended Svg file detection http://svn.apache.org/viewvc?view=revision&revision=1230531 #118529# solve break converters and convert commands for OLEs and images http://svn.apache.org/viewvc?view=revision&revision=1186168 svg: added WaE changes from branch svgreplacement to trunc http://svn.apache.org/viewvc?view=revision&revision=1222974 svg: corrected missing member initialization http://svn.apache.org/viewvc?view=revision&revision=1226134 fix for #118525#: Using primitives for chart sub-geometry visualisation http://svn.apache.org/viewvc?view=revision&revision=1226879 #118898# Adapted ImpGraphic::ImplGetBitmap to correctly convert metafiles to bitmapEx ... http://svn.apache.org/viewvc?view=revision&revision=1293316 fix for #118525#: removed no longer used variable maOriginalMapMode, one more exception eliminated http://svn.apache.org/viewvc?view=revision&revision=1227097 #16758# Added buffering to the VDev usages of the VclProcessor2D derivates... http://svn.apache.org/viewvc?view=revision&revision=1229521 #116758# Secured VDev buffer device to Vcl deinit http://svn.apache.org/viewvc?view=revision&revision=1230574 #116758# added remembering allocated VDevs for VDevBuffer to be able to also delete these when vcl goes down; it should never happen, but You never know http://svn.apache.org/viewvc?view=revision&revision=1230927 #118730# Changed SvgClipPathNode to use MaskPrimitive2D for primitive representation instead of TransparencePrimitive2D http://svn.apache.org/viewvc?view=revision&revision=1231198 #118822# secured 3D geometry creation (slices) by subdividing the 2D source polyPolygon early http://svn.apache.org/viewvc?view=revision&revision=1234749 #118829# enhanced Svg gradient quality, obstacles avoided http://svn.apache.org/viewvc?view=revision&revision=1235361 #118834# Unified usage of TextBreakupHelper as single tooling class for i18n text primitive breakup http://svn.apache.org/viewvc?view=revision&revision=1236110 #118853# added square pixel size limit to conversion of TransparencePrimitive2D to Metafile action http://svn.apache.org/viewvc?view=revision&revision=1237656 #118824# coreccted mirroring and boundrect when the graphicmanager is used for bitmap output http://svn.apache.org/viewvc?view=revision&revision=1240097 #115092# Corrected VclProcessor2D::RenderPolygonStrokePrimitive2D for various optimization scenarios http://svn.apache.org/viewvc?view=revision&revision=1241434 #118783# Corrected errors in ID strings, corrected Svg line/fill export, corrected polygon close state http://svn.apache.org/viewvc?view=revision&revision=1232006 #118796# corrected null-pointer usage in SVG text exporter http://svn.apache.org/viewvc?view=revision&revision=1240262 #118729# Use GraphicStreamUrl and GraphicUrl to allow multi image import with linked graphics, too http://svn.apache.org/viewvc?view=revision&revision=1229962 #118898# corrected error in GDIMetaFile::GetBoundRect in handling MetaFloatTransparentAction http://svn.apache.org/viewvc?view=revision&revision=1293349 #118855# Corrected handling of possibly created empty clipRegions after PolyPolygon clipping http://svn.apache.org/viewvc?view=revision&revision=1237725 #115962# Better (but not yet optimal, see comments in task) handling of MetaFloatTransparentAction in PDF export http://svn.apache.org/viewvc?view=revision&revision=1241078 IP clearance: #118466# This patch removes librsvg, libcroco, libgsf, ... http://svn.apache.org/viewvc?view=revision&revision=1200879 118779# Added svg content streaming in/out to ImpGraphic stream operators http://svn.apache.org/viewvc?view=revision&revision=1231908 linecap: correctons for WaE and mac drawing http://svn.apache.org/viewvc?view=revision&revision=1232793 svg: uses current system Dpi for Svg replacement image creation http://svn.apache.org/viewvc?view=revision&revision=1233948 Patches contributed by Mathias Bauer (and others) gnumake4 work variously http://svn.apache.org/viewvc?view=revision&revision=1394326 http://svn.apache.org/viewvc?view=revision&revision=1396797 http://svn.apache.org/viewvc?view=revision&revision=1397315 http://svn.apache.org/viewvc?view=revision&revision=1394326 Remove duplicate header includes. cws mba34issues01: #i117720#: convert assertion into warning http://svn.apache.org/viewvc?view=revision&revision=1172352 118485 - Styles for OLEs are not saved. Submitted by Armin Le Grand. http://svn.apache.org/viewvc?view=revision&revision=1182166 cws mba34issues01: #i117714#: remove assertion http://svn.apache.org/viewvc?view=revision&revision=1172357 Patch contributed by Jurgen Schmidt add some additional checks to ensure proper reading operations http://svn.apache.org/viewvc?view=revision&revision=1209022 mostly prefer our stream / bounds checking work. Patches contributed by Herbert Duerr #i118816# add clarifying comment regarding Font::*Color*() methods http://svn.apache.org/viewvc?view=revision&revision=1233833 extend macro->string handling for empty strings http://svn.apache.org/viewvc?view=revision&revision=1175801 avoid magic constants for SALCOLOR_NONE http://svn.apache.org/viewvc?view=revision&revision=1177543 initialize slant properly in ImplFontMetricData constructor (author=iorsh) http://svn.apache.org/viewvc?view=revision&revision=1177551 #i118675# make check for extension updates more stable http://svn.apache.org/viewvc?view=revision&revision=1214797 #a118617# remove VBasicEventListener.dll binary There are no known users depending on its CLSID http://svn.apache.org/viewvc?view=revision&revision=1203697 Patches contributed by Ariel Constenla-Haile Fix build breaker on Linux/gcc http://svn.apache.org/viewvc?view=revision&revision=1221104 Fix crash when trying to instantiate css.graphic.GraphicRasterizer_RSVG http://svn.apache.org/viewvc?view=revision&revision=1215559 Patches contributed by Oliver-Rainer Wittmann sw34bf06: #i117962# - method <SwFlyFrm::IsPaint(..)> - consider instances of <SwFlyDrawObj> http://svn.apache.org/viewvc?view=revision&revision=1172120 sw34bf06: #i117783# - Writer's implementation of XPagePrintable - apply print settings to new printing routines http://svn.apache.org/viewvc?view=revision&revision=1172115 gnumake4 work variously from Hans-Joachim Lankenau http://svn.apache.org/viewvc?view=revision&revision=1397315 http://svn.apache.org/viewvc?view=revision&revision=1396797 http://svn.apache.org/viewvc?view=revision&revision=1396782 http://svn.apache.org/viewvc?view=revision&revision=1394707 plus some amount of re-splitting of legacy headers. Patch contributed by Pavel Janik WaE: Remove unused variables. http://svn.apache.org/viewvc?view=revision&revision=1230697 Patches contributed by Takashi Ono mingwport35: i#117795: MinGW port fix for vcl2gnumake http://svn.apache.org/viewvc?view=revision&revision=1172091 mingwport35: i#117795: MinGW port fix for vcl2gnumake http://svn.apache.org/viewvc?view=revision&revision=1172091 Patch contributed by Christian Lippka impress212: #i98044# re enable Text menu for outline and title shapes http://svn.apache.org/viewvc?view=revision&revision=1167639 Patch contributed by Andre Fischer 118674: Made category B code optional and disabled by default. http://svn.apache.org/viewvc?view=revision&revision=1215131 118881: Ignore empty paragraphs after bullets. http://svn.apache.org/viewvc?view=revision&revision=1296205 Patches contributed by Philipp Lohmann ooo340fixes: #i117780# use rtl allocator http://svn.apache.org/viewvc?view=revision&revision=1172087 ooo34gsl02: #i117807# fix an off by one error (index actually inside the pfb section header) http://svn.apache.org/viewvc?view=revision&revision=1167576 various cleanups, related compilation fixes, warning cleanups, re-working of obsolete stl template pieces to use boost instead, changed string classes, re-adapt KDE about data, about dialog, fixing warnings, and other fixes & improvements. Disable svg import / render for about/ branding code-paths for now. Restore full icon theme set. Remove OS/2 conditionals and sources. Remove conflicting gtk/full-screen monitors support. Retain existing svg rasterizer files - temporarily disabled. Standardize stringificaiton and fixup dllpostfix issues. Rename SvgGradientHelper::== to equalTo to avoid overloading issues. Use the flat GdiPlus API for LineCaps calls.
2012-10-09 12:22:23 +01:00
/*
* 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 .
*/
2000-09-18 16:07:07 +00:00
2000-09-18 16:07:07 +00:00
#include <string.h>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <vcl/mnemonic.hxx>
2000-09-18 16:07:07 +00:00
#include <vcl/unohelp.hxx>
#include <com/sun/star/i18n/XCharacterClassification.hpp>
#include <i18npool/mslangid.hxx>
2000-09-18 16:07:07 +00:00
using namespace ::com::sun::star;
// =======================================================================
2002-05-16 10:22:20 +00:00
MnemonicGenerator::MnemonicGenerator()
2000-09-18 16:07:07 +00:00
{
memset( maMnemonics, 1, sizeof( maMnemonics ) );
}
// -----------------------------------------------------------------------
sal_uInt16 MnemonicGenerator::ImplGetMnemonicIndex( sal_Unicode c )
2000-09-18 16:07:07 +00:00
{
static sal_uInt16 const aImplMnemonicRangeTab[MNEMONIC_RANGES*2] =
2000-09-18 16:07:07 +00:00
{
MNEMONIC_RANGE_1_START, MNEMONIC_RANGE_1_END,
MNEMONIC_RANGE_2_START, MNEMONIC_RANGE_2_END,
MNEMONIC_RANGE_3_START, MNEMONIC_RANGE_3_END,
MNEMONIC_RANGE_4_START, MNEMONIC_RANGE_4_END
};
sal_uInt16 nMnemonicIndex = 0;
for ( sal_uInt16 i = 0; i < MNEMONIC_RANGES; i++ )
2000-09-18 16:07:07 +00:00
{
if ( (c >= aImplMnemonicRangeTab[i*2]) &&
(c <= aImplMnemonicRangeTab[i*2+1]) )
return nMnemonicIndex+c-aImplMnemonicRangeTab[i*2];
nMnemonicIndex += aImplMnemonicRangeTab[i*2+1]-aImplMnemonicRangeTab[i*2];
}
return MNEMONIC_INDEX_NOTFOUND;
}
// -----------------------------------------------------------------------
2002-05-16 10:22:20 +00:00
sal_Unicode MnemonicGenerator::ImplFindMnemonic( const XubString& rKey )
2000-09-18 16:07:07 +00:00
{
xub_StrLen nIndex = 0;
while ( (nIndex = rKey.Search( MNEMONIC_CHAR, nIndex )) != STRING_NOTFOUND )
{
sal_Unicode cMnemonic = rKey.GetChar( nIndex+1 );
if ( cMnemonic != MNEMONIC_CHAR )
return cMnemonic;
nIndex += 2;
}
return 0;
}
// -----------------------------------------------------------------------
2002-05-16 10:22:20 +00:00
void MnemonicGenerator::RegisterMnemonic( const XubString& rKey )
2000-09-18 16:07:07 +00:00
{
const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetUILanguageTag().getLocale();
uno::Reference < i18n::XCharacterClassification > xCharClass = GetCharClass();
2000-09-18 16:07:07 +00:00
// Don't crash even when we don't have access to i18n service
if ( !xCharClass.is() )
return;
2000-09-18 16:07:07 +00:00
XubString aKey = xCharClass->toUpper( rKey, 0, rKey.Len(), rLocale );
// If we find a Mnemonic, set the flag. In other case count the
// characters, because we need this to set most as possible
// Mnemonics
sal_Unicode cMnemonic = ImplFindMnemonic( aKey );
if ( cMnemonic )
{
sal_uInt16 nMnemonicIndex = ImplGetMnemonicIndex( cMnemonic );
2000-09-18 16:07:07 +00:00
if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND )
maMnemonics[nMnemonicIndex] = 0;
}
else
{
xub_StrLen nIndex = 0;
xub_StrLen nLen = aKey.Len();
while ( nIndex < nLen )
{
sal_Unicode c = aKey.GetChar( nIndex );
sal_uInt16 nMnemonicIndex = ImplGetMnemonicIndex( c );
2000-09-18 16:07:07 +00:00
if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND )
{
if ( maMnemonics[nMnemonicIndex] && (maMnemonics[nMnemonicIndex] < 0xFF) )
maMnemonics[nMnemonicIndex]++;
}
nIndex++;
}
}
}
// -----------------------------------------------------------------------
sal_Bool MnemonicGenerator::CreateMnemonic( XubString& rKey )
2000-09-18 16:07:07 +00:00
{
if ( !rKey.Len() || ImplFindMnemonic( rKey ) )
return sal_False;
2000-09-18 16:07:07 +00:00
const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetUILanguageTag().getLocale();
uno::Reference < i18n::XCharacterClassification > xCharClass = GetCharClass();
2000-09-18 16:07:07 +00:00
// Don't crash even when we don't have access to i18n service
if ( !xCharClass.is() )
return sal_False;
2000-09-18 16:07:07 +00:00
XubString aKey = xCharClass->toUpper( rKey, 0, rKey.Len(), rLocale );
sal_Bool bChanged = sal_False;
2000-09-18 16:07:07 +00:00
xub_StrLen nLen = aKey.Len();
bool bCJK = MsLangId::isCJK(Application::GetSettings().GetUILanguageTag().getLanguageType());
// #107889# in CJK versions ALL strings (even those that contain latin characters)
// will get mnemonics in the form: xyz (M)
// thus steps 1) and 2) are skipped for CJK locales
// #110720#, avoid CJK-style mnemonics for latin-only strings that do not contain useful mnemonic chars
if( bCJK )
{
sal_Bool bLatinOnly = sal_True;
sal_Bool bMnemonicIndexFound = sal_False;
sal_Unicode c;
xub_StrLen nIndex;
for( nIndex=0; nIndex < nLen; nIndex++ )
{
c = aKey.GetChar( nIndex );
if ( ((c >= 0x3000) && (c <= 0xD7FF)) || // cjk
((c >= 0xFF61) && (c <= 0xFFDC)) ) // halfwidth forms
{
bLatinOnly = sal_False;
break;
}
if( ImplGetMnemonicIndex( c ) != MNEMONIC_INDEX_NOTFOUND )
bMnemonicIndexFound = sal_True;
}
if( bLatinOnly && !bMnemonicIndexFound )
return sal_False;
}
2001-06-08 12:52:07 +00:00
int nCJK = 0;
sal_uInt16 nMnemonicIndex;
2000-09-18 16:07:07 +00:00
sal_Unicode c;
xub_StrLen nIndex = 0;
if( !bCJK )
2000-09-18 16:07:07 +00:00
{
// 1) first try the first character of a word
do
2001-06-08 12:52:07 +00:00
{
c = aKey.GetChar( nIndex );
2001-06-08 12:52:07 +00:00
if ( nCJK != 2 )
2000-09-18 16:07:07 +00:00
{
if ( ((c >= 0x3000) && (c <= 0xD7FF)) || // cjk
((c >= 0xFF61) && (c <= 0xFFDC)) ) // halfwidth forms
nCJK = 1;
else if ( ((c >= 0x0030) && (c <= 0x0039)) || // digits
((c >= 0x0041) && (c <= 0x005A)) || // latin capitals
((c >= 0x0061) && (c <= 0x007A)) || // latin small
((c >= 0x0370) && (c <= 0x037F)) || // greek numeral signs
((c >= 0x0400) && (c <= 0x04FF)) ) // cyrillic
nCJK = 2;
2000-09-18 16:07:07 +00:00
}
nMnemonicIndex = ImplGetMnemonicIndex( c );
if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND )
{
if ( maMnemonics[nMnemonicIndex] )
{
maMnemonics[nMnemonicIndex] = 0;
rKey.Insert( MNEMONIC_CHAR, nIndex );
bChanged = sal_True;
break;
2000-09-18 16:07:07 +00:00
}
}
// Search for next word
do
{
nIndex++;
c = aKey.GetChar( nIndex );
if ( c == ' ' )
break;
}
while ( nIndex < nLen );
2000-09-18 16:07:07 +00:00
nIndex++;
}
while ( nIndex < nLen );
// 2) search for a unique/uncommon character
if ( !bChanged )
2000-09-18 16:07:07 +00:00
{
sal_uInt16 nBestCount = 0xFFFF;
sal_uInt16 nBestMnemonicIndex = 0;
xub_StrLen nBestIndex = 0;
nIndex = 0;
do
{
c = aKey.GetChar( nIndex );
nMnemonicIndex = ImplGetMnemonicIndex( c );
if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND )
{
if ( maMnemonics[nMnemonicIndex] )
{
if ( maMnemonics[nMnemonicIndex] < nBestCount )
{
nBestCount = maMnemonics[nMnemonicIndex];
nBestIndex = nIndex;
nBestMnemonicIndex = nMnemonicIndex;
if ( nBestCount == 2 )
break;
}
}
}
nIndex++;
}
while ( nIndex < nLen );
if ( nBestCount != 0xFFFF )
{
maMnemonics[nBestMnemonicIndex] = 0;
rKey.Insert( MNEMONIC_CHAR, nBestIndex );
bChanged = sal_True;
}
2000-09-18 16:07:07 +00:00
}
}
else
nCJK = 1;
2000-09-18 16:07:07 +00:00
// 3) Add English Mnemonic for CJK Text
2001-06-08 12:52:07 +00:00
if ( !bChanged && (nCJK == 1) && rKey.Len() )
{
// Append Ascii Mnemonic
for ( c = MNEMONIC_RANGE_2_START; c <= MNEMONIC_RANGE_2_END; c++ )
{
nMnemonicIndex = ImplGetMnemonicIndex( c );
if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND )
{
if ( maMnemonics[nMnemonicIndex] )
{
maMnemonics[nMnemonicIndex] = 0;
rtl::OUString aStr = rtl::OUStringBuffer().
append('(').append(MNEMONIC_CHAR).append(c).
append(')').makeStringAndClear();
2001-06-08 12:52:07 +00:00
nIndex = rKey.Len();
if( nIndex >= 2 )
{
static sal_Unicode cGreaterGreater[] = { 0xFF1E, 0xFF1E };
if ( rKey.EqualsAscii( ">>", nIndex-2, 2 ) ||
rKey.Equals( cGreaterGreater, nIndex-2, 2 ) )
nIndex -= 2;
}
if( nIndex >= 3 )
{
static sal_Unicode cDotDotDot[] = { 0xFF0E, 0xFF0E, 0xFF0E };
if ( rKey.EqualsAscii( "...", nIndex-3, 3 ) ||
rKey.Equals( cDotDotDot, nIndex-3, 3 ) )
nIndex -= 3;
}
if( nIndex >= 1)
{
sal_Unicode cLastChar = rKey.GetChar( nIndex-1 );
if ( (cLastChar == ':') || (cLastChar == 0xFF1A) ||
(cLastChar == '.') || (cLastChar == 0xFF0E) ||
(cLastChar == '?') || (cLastChar == 0xFF1F) ||
(cLastChar == ' ') )
nIndex--;
}
2001-06-08 12:52:07 +00:00
rKey.Insert( aStr, nIndex );
bChanged = sal_True;
2001-06-08 12:52:07 +00:00
break;
}
}
}
}
// #i87415# Duplicates mnemonics are bad for consistent keyboard accessibility
// It's probably better to not have mnemonics for some widgets, than to have ambiguous ones.
// if( ! bChanged )
// {
// /*
// * #97809# if all else fails use the first character of a word
// * anyway and live with duplicate mnemonics
// */
// nIndex = 0;
// do
// {
// c = aKey.GetChar( nIndex );
//
// nMnemonicIndex = ImplGetMnemonicIndex( c );
// if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND )
// {
// maMnemonics[nMnemonicIndex] = 0;
// rKey.Insert( MNEMONIC_CHAR, nIndex );
// bChanged = sal_True;
// break;
// }
//
// // Search for next word
// do
// {
// nIndex++;
// c = aKey.GetChar( nIndex );
// if ( c == ' ' )
// break;
// }
// while ( nIndex < nLen );
// nIndex++;
// }
// while ( nIndex < nLen );
// }
2000-09-18 16:07:07 +00:00
return bChanged;
}
2001-06-08 12:52:07 +00:00
// -----------------------------------------------------------------------
2002-05-16 10:22:20 +00:00
uno::Reference< i18n::XCharacterClassification > MnemonicGenerator::GetCharClass()
2000-09-18 16:07:07 +00:00
{
if ( !mxCharClass.is() )
mxCharClass = vcl::unohelper::CreateCharacterClassification();
return mxCharClass;
2000-09-18 16:07:07 +00:00
}
// -----------------------------------------------------------------------
String MnemonicGenerator::EraseAllMnemonicChars( const String& rStr )
{
String aStr = rStr;
xub_StrLen nLen = aStr.Len();
xub_StrLen i = 0;
while ( i < nLen )
{
if ( aStr.GetChar( i ) == '~' )
{
// check for CJK-style mnemonic
if( i > 0 && (i+2) < nLen )
{
sal_Unicode c = aStr.GetChar(i+1);
if( aStr.GetChar( i-1 ) == '(' &&
aStr.GetChar( i+2 ) == ')' &&
c >= MNEMONIC_RANGE_2_START && c <= MNEMONIC_RANGE_2_END )
{
aStr.Erase( i-1, 4 );
nLen -= 4;
i--;
continue;
}
}
// remove standard mnemonics
aStr.Erase( i, 1 );
nLen--;
}
else
i++;
}
return aStr;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */