kexi

identifier.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003-2005 Jaroslaw Staniek <js@iidea.pl>
00003    Copyright (C) 2005 Martin Ellis <martin.ellis@kdemail.net>
00004 
00005    This program is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this program; see the file COPYING.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "identifier.h"
00022 #include <kstaticdeleter.h>
00023 #include <qdict.h>
00024 
00025 using namespace KexiUtils;
00026 
00027 bool KexiUtils::isIdentifier(const QString& s)
00028 {
00029     uint i;
00030     for (i=0; i<s.length(); i++) {
00031         QChar c = s.at(i).lower();
00032         if (!(c=='_' || c>='a' && c<='z' || i>0 && c>='0' && c<='9'))
00033             break;
00034     }
00035     return i>0 && i==s.length();
00036 }
00037 
00038 QString KexiUtils::string2FileName(const QString &s)
00039 {
00040     QString fn = s.simplifyWhiteSpace();
00041     fn.replace(' ',"_"); fn.replace('$',"_");
00042     fn.replace('\\',"-"); fn.replace('/',"-"); 
00043     fn.replace(':',"-"); fn.replace('*',"-"); 
00044     return fn;
00045 }
00046 
00047 // These are in pairs - first the non-latin character in UTF-8,
00048 // the second is the latin character(s) to appear in identifiers.
00049 static const char* string2Identifier_table[] = {
00050 /* 1. Polish characters */
00051 "Ą", "A",  "Ć", "C",  "Ę", "E",
00052 "Ł", "L",  "Ń", "N",  "Ó", "O",
00053 "Ś", "S",  "Ź", "Z",  "Ż", "Z",
00054 "ą", "a",  "ć", "c",  "ę", "e",
00055 "ł", "l",  "ń", "n",  "ó", "o",
00056 "ś", "s",  "ź", "z",  "ż", "z",
00057 
00058 /* 2. The mappings of the german "umlauts" to their 2-letter equivalents:
00059   (Michael Drüing <michael at drueing.de>)
00060 
00061  Note that ß->ss is AFAIK not always correct transliteration, for example
00062  "Maße" and "Masse" is different, the first meaning "measurements" (as
00063  plural of "Maß" meaning "measurement"), the second meaning "(physical)
00064  mass". They're also pronounced dirrefently, the first one is longer, the
00065  second one short. */
00069 "Ä", "Ae",
00070 "Ö", "Oe",
00071 "Ü", "Ue",
00072 "ä", "ae",
00073 "ö", "oe",
00074 "ü", "ue",
00075 "ß", "ss",
00076  
00077 /* 3. The part of Serbian Cyrillic which is shared with other Cyrillics but 
00078  that doesn't mean I am sure that eg. Russians or Bulgarians would do the 
00079  same. (Chusslove Illich <caslav.ilic at gmx.net>) */
00080 "а", "a",
00081 "б", "b",
00082 "в", "v",
00083 "г", "g",
00084 "д", "d",
00085 "е", "e",
00086 "ж", "z",
00087 "з", "z",
00088 "и", "i",
00089 "к", "k",
00090 "л", "l",
00091 "м", "m",
00092 "н", "n",
00093 "о", "o",
00094 "п", "p",
00095 "р", "r",
00096 "с", "s",
00097 "т", "t",
00098 "у", "u",
00099 "ф", "f",
00100 "х", "h",
00101 "ц", "c",
00102 "ч", "c",
00103 "ш", "s",
00104 "А", "A",
00105 "Б", "B",
00106 "В", "V",
00107 "Г", "G",
00108 "Д", "D",
00109 "Е", "E",
00110 "Ж", "Z",
00111 "З", "Z",
00112 "И", "I",
00113 "К", "K",
00114 "Л", "L",
00115 "М", "M",
00116 "Н", "N",
00117 "О", "O",
00118 "П", "P",
00119 "Р", "R",
00120 "С", "S",
00121 "Т", "T",
00122 "У", "U",
00123 "Ф", "F",
00124 "Х", "H",
00125 "Ц", "C",
00126 "Ч", "C",
00127 "Ш", "S",
00128 // 3.1. The Serbian-specific Cyrillic characters:
00129 "ђ", "dj",
00130 "ј", "j",
00131 "љ", "lj",
00132 "њ", "nj",
00133 "ћ", "c",
00134 "џ", "dz",
00135 "Ђ", "Dj",
00136 "Ј", "J",
00137 "Љ", "Lj",
00138 "Њ", "Nj",
00139 "Ћ", "C",
00140 "Џ", "Dz",
00141 // 3.2. The non-ASCII Serbian Latin characters:
00142 "đ", "dj",
00143 "ž", "z",
00144 "ć", "c",
00145 "č", "c",
00146 "š", "s",
00147 "Đ", "Dj",
00148 "Ž", "Z",
00149 "Ć", "C",
00150 "Č", "C",
00151 "Š", "S",
00152 // 4. Czech characters (cs_CZ, Michal Svec)
00153  "Á", "A",
00154  "Č", "C",
00155  "Ď", "D",
00156  "É", "E",
00157  "Ě", "E",
00158  "Í", "I",
00159  "Ň", "N",
00160  "Ó", "O",
00161  "Ř", "R",
00162  "Š", "S",
00163  "Ť", "T",
00164  "Ú", "U",
00165  "Ů", "U",
00166  "Ý", "Y",
00167  "Ž", "Z",
00168  "á", "a",
00169  "č", "c",
00170  "ď", "d",
00171  "é", "e",
00172  "ě", "e",
00173  "í", "i",
00174  "ň", "n",
00175  "ó", "o",
00176  "ř", "r",
00177  "š", "s",
00178  "ť", "t",
00179  "ú", "u",
00180  "ů", "u",
00181  "ý", "y",
00182  "ž", "z",
00183 // END.
00184 0
00185 };
00186 
00188 static KStaticDeleter< QDict<QCString> > string2Identifier_deleter;
00189 static QDict<QCString>* string2Identifier_dict = 0;
00190 
00191 inline QString char2Identifier(const QChar& c)
00192 {
00193     if ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_')
00194         return QString(c);
00195     else {
00196         if (!string2Identifier_dict) {
00197             //build dictionary for later use
00198             string2Identifier_deleter.setObject( string2Identifier_dict, new QDict<QCString>(1009) );
00199             string2Identifier_dict->setAutoDelete(true);
00200             for (const char **p = string2Identifier_table; *p; p+=2) {
00201                 string2Identifier_dict->replace( /* replace, not insert because there may be duplicates */
00202                     QString::fromUtf8(*p), new QCString(*(p+1)) );
00203             }
00204         }
00205         const QCString *fixedChar = string2Identifier_dict->find(c);
00206         if (fixedChar)
00207             return *fixedChar;
00208     }
00209     return QString(QChar('_'));
00210 }
00211 
00212 QString KexiUtils::string2Identifier(const QString &s)
00213 {
00214     QString r, id = s.simplifyWhiteSpace();
00215     if (id.isEmpty())
00216         return id;
00217     r.reserve(id.length());
00218 //      return "_";
00219     id.replace(' ',"_");
00220     QChar c = id[0];
00221 
00222     if (c>='0' && c<='9') {
00223         r+='_';
00224         r+=c;
00225     } else
00226         r+=char2Identifier(c);
00227 
00228     for (uint i=1; i<id.length(); i++)
00229         r+=char2Identifier(id.at(i));
00230     return r;
00231 }
00232 
00233 //--------------------------------------------------------------------------------
00234 
00235 QString KexiUtils::identifierExpectedMessage(const QString &valueName, const QVariant& v)
00236 {
00237     return "<p>"+i18n("Value of \"%1\" column must be an identifier.").arg(valueName)
00238         +"</p><p>"+i18n("\"%1\" is not a valid identifier.").arg(v.toString())+"</p>";
00239 }
00240 
00241 //--------------------------------------------------------------------------------
00242 
00243 IdentifierValidator::IdentifierValidator(QObject * parent, const char * name)
00244 : Validator(parent,name)
00245 {
00246 }
00247 
00248 IdentifierValidator::~IdentifierValidator()
00249 {
00250 }
00251 
00252 QValidator::State IdentifierValidator::validate( QString& input, int& pos ) const
00253 {
00254     uint i;
00255     for (i=0; i<input.length() && input.at(i)==' '; i++)
00256         ;
00257     pos -= i; //i chars will be removed from beginning
00258     if (i<input.length() && input.at(i)>='0' && input.at(i)<='9')
00259         pos++; //_ will be added at the beginning
00260     bool addspace = (input.right(1)==" ");
00261     input = string2Identifier(input);
00262     if (addspace)
00263         input += "_";
00264     if((uint)pos>input.length())
00265         pos=input.length();
00266     return input.isEmpty() ? Valid : Acceptable;
00267 }
00268 
00269 Validator::Result IdentifierValidator::internalCheck(
00270     const QString &valueName, const QVariant& v, 
00271     QString &message, QString & /*details*/)
00272 {
00273     if (isIdentifier(v.toString()))
00274         return Validator::Ok;
00275     message = identifierExpectedMessage(valueName, v);
00276     return Validator::Error;
00277 }
00278 
KDE Home | KDE Accessibility Home | Description of Access Keys