Added support for UTF-8 keyboard entry and completion of location labels.

ver1_5_1
Christophe Teyssier 2004-01-11 17:15:26 +00:00
parent 5e3d7f157b
commit ed0a3aa3dd
14 changed files with 145 additions and 59 deletions

View File

@ -620,7 +620,7 @@ Body* PlanetarySystem::find(string _name, bool deepSearch) const
for (vector<Body*>::const_iterator iter = satellites.begin();
iter != satellites.end(); iter++)
{
if (compareIgnoringCase((*iter)->getName(), _name) == 0)
if (UTF8StringCompare((*iter)->getName(), _name) == 0)
{
return *iter;
}
@ -657,10 +657,11 @@ bool PlanetarySystem::traverse(TraversalFunc func, void* info) const
std::vector<std::string> PlanetarySystem::getCompletion(const std::string& _name, bool rec) const
{
std::vector<std::string> completion;
for (vector<Body*>::const_iterator iter = satellites.begin();
iter != satellites.end(); iter++)
{
if (compareIgnoringCase((*iter)->getName(), _name, _name.length()) == 0)
if (UTF8StringCompare((*iter)->getName(), _name, _name.length()) == 0)
{
completion.push_back((*iter)->getName());
}

View File

@ -449,13 +449,21 @@ Selection Simulation::findObjectFromPath(string s)
}
std::vector<std::string> Simulation::getObjectCompletion(string s)
std::vector<std::string> Simulation::getObjectCompletion(string s, bool withLocations)
{
Selection path[2];
int nPathEntries = 0;
if (!selection.empty())
path[nPathEntries++] = selection;
if (!selection.empty()) {
if (selection.getType() == Selection::Type_Location)
{
path[nPathEntries++] = Selection(selection.location()->getParentBody());
}
else
{
path[nPathEntries++] = selection;
}
}
if (closestSolarSystem != NULL &&
closestSolarSystem != universe->getSolarSystem(selection))
@ -463,7 +471,7 @@ std::vector<std::string> Simulation::getObjectCompletion(string s)
path[nPathEntries++] = Selection(closestSolarSystem->getStar());
}
return universe->getCompletionPath(s, path, nPathEntries);
return universe->getCompletionPath(s, path, nPathEntries, withLocations);
}

View File

@ -59,7 +59,7 @@ class Simulation
void selectPlanet(int);
Selection findObject(std::string s);
Selection findObjectFromPath(std::string s);
std::vector<std::string> getObjectCompletion(std::string s);
std::vector<std::string> getObjectCompletion(std::string s, bool withLocations = false);
void gotoSelection(double gotoTime,
Vec3f up, astro::CoordinateSystem upFrame);
void gotoSelection(double gotoTime, double distance,

View File

@ -17,6 +17,7 @@
#include <celutil/util.h>
#include <celutil/debug.h>
#include <celutil/utf8.h>
#include "celestia.h"
#include "star.h"
#include "starname.h"
@ -97,7 +98,7 @@ std::vector<std::string> StarNameDatabase::getCompletion(const std::string& name
for (NameIndex::const_iterator iter = nameIndex.begin();
iter != nameIndex.end() ; iter++)
{
if (!compareIgnoringCase(iter->first, name, name.length()))
if (!UTF8StringCompare(iter->first, name, name.length()))
{
completion.push_back(iter->first);
}

View File

@ -12,6 +12,7 @@
#include <celmath/mathlib.h>
#include <celmath/vecmath.h>
#include <celmath/intersect.h>
#include <celutil/utf8.h>
#include "astro.h"
#include "3dsmesh.h"
#include "meshmanager.h"
@ -818,7 +819,7 @@ Selection Universe::find(const string& s,
for (DeepSkyCatalog::const_iterator iter = deepSkyCatalog->begin();
iter != deepSkyCatalog->end(); iter++)
{
if (compareIgnoringCase((*iter)->getName(), s) == 0)
if (UTF8StringCompare((*iter)->getName(), s) == 0)
return Selection(*iter);
}
}
@ -879,13 +880,24 @@ Selection Universe::findPath(const string& s,
std::vector<std::string> Universe::getCompletion(const string& s,
Selection* contexts,
int nContexts)
int nContexts,
bool withLocations)
{
std::vector<std::string> completion;
// solar bodies first
for (int i = 0; i < nContexts; i++)
{
if (withLocations && contexts[i].getType() == Selection::Type_Body) {
std::vector<Location*>* locations = contexts[i].body()->getLocations();
for (vector<Location*>::const_iterator iter = locations->begin();
iter != locations->end(); iter++)
{
if (!UTF8StringCompare(s, (*iter)->getName(), s.length()))
completion.push_back((*iter)->getName());
}
}
SolarSystem* sys = getSolarSystem(contexts[i]);
if (sys != NULL)
{
@ -905,7 +917,7 @@ std::vector<std::string> Universe::getCompletion(const string& s,
for (DeepSkyCatalog::const_iterator iter = deepSkyCatalog->begin();
iter != deepSkyCatalog->end(); iter++)
{
if (compareIgnoringCase((*iter)->getName(), s, s.length()) == 0)
if (UTF8StringCompare((*iter)->getName(), s, s.length()) == 0)
completion.push_back(Selection(*iter).getName());
}
}
@ -919,13 +931,16 @@ std::vector<std::string> Universe::getCompletion(const string& s,
std::vector<std::string> Universe::getCompletionPath(const string& s,
Selection* contexts,
int nContexts)
int nContexts,
bool withLocations)
{
std::vector<std::string> completion;
std::vector<std::string> locationCompletion;
string::size_type pos = s.rfind('/', s.length());
if (pos == string::npos)
return getCompletion(s, contexts, nContexts);
return getCompletion(s, contexts, nContexts, withLocations);
string base(s, 0, pos);
Selection sel = findPath(base, contexts, nContexts);
@ -943,6 +958,16 @@ std::vector<std::string> Universe::getCompletionPath(const string& s,
if (sel.getType() == Selection::Type_Body)
{
worlds = sel.body()->getSatellites();
if (withLocations) {
std::vector<Location*>* locations = sel.body()->getLocations();
string search = s.substr(pos + 1);
for (vector<Location*>::const_iterator iter = locations->begin();
iter != locations->end(); iter++)
{
if (!UTF8StringCompare(search, (*iter)->getName(), search.length()))
locationCompletion.push_back((*iter)->getName());
}
}
}
else if (sel.getType() == Selection::Type_Star)
{
@ -953,7 +978,8 @@ std::vector<std::string> Universe::getCompletionPath(const string& s,
if (worlds != NULL)
{
return worlds->getCompletion(s.substr(pos + 1), false);
completion = worlds->getCompletion(s.substr(pos + 1), false);
completion.insert(completion.end(), locationCompletion.begin(), locationCompletion.end());
}
return completion;

View File

@ -62,10 +62,12 @@ class Universe
std::vector<std::string> getCompletion(const std::string& s,
Selection* contexts = NULL,
int nContexts = 0);
int nContexts = 0,
bool withLocations = false);
std::vector<std::string> getCompletionPath(const std::string& s,
Selection* contexts = NULL,
int nContexts = 0);
int nContexts = 0,
bool withLocations = false);
SolarSystem* getNearestSolarSystem(const UniversalCoord& position) const;

View File

@ -1021,9 +1021,19 @@ void CelestiaCore::keyUp(int key, int)
}
void CelestiaCore::charEntered(char c)
{
char C[2];
C[0] = c;
C[1] = '\0';
charEntered(C);
}
void CelestiaCore::charEntered(const char *c_p)
{
Observer* observer = sim->getActiveObserver();
char c = *c_p;
#ifdef CELX
if (celxScript != NULL && (textEnterMode & KbPassToScript))
{
@ -1036,10 +1046,12 @@ void CelestiaCore::charEntered(char c)
if (textEnterMode & KbAutoComplete)
{
if ( c == ' ' || isalpha(c) || isdigit(c) || ispunct(c))
wchar_t wc = NULL;
UTF8Decode(c_p, 0, strlen(c_p), wc);
if ( wc && (iswalpha(wc) || iswdigit(wc) || iswpunct(c)) )
{
typedText += c;
typedTextCompletion = sim->getObjectCompletion(typedText);
typedText += std::string(c_p);
typedTextCompletion = sim->getObjectCompletion(typedText, renderer->getLabelMode() & Renderer::LocationLabels);
typedTextCompletionIdx = -1;
#ifdef AUTO_COMPLETION
if (typedTextCompletion.size() == 1)
@ -1061,10 +1073,16 @@ void CelestiaCore::charEntered(char c)
do
{
#endif
// We remove bytes like b10xxx xxxx at the end of typeText
// these are guarantied to not be the first byte of a UTF-8 char
while (typedText.size() && ((typedText[typedText.size() - 1] & 0xC0) == 0x80)) {
typedText = string(typedText, 0, typedText.size() - 1);
}
// We then remove the first byte of the last UTF-8 char of typedText.
typedText = string(typedText, 0, typedText.size() - 1);
if (typedText.size() > 0)
{
typedTextCompletion = sim->getObjectCompletion(typedText);
typedTextCompletion = sim->getObjectCompletion(typedText, renderer->getLabelMode() & Renderer::LocationLabels);
} else {
typedTextCompletion.clear();
}

View File

@ -180,6 +180,7 @@ class CelestiaCore // : public Watchable<CelestiaCore>
void setHistoryCurrent(std::vector<Url>::size_type curr);
// event processing methods
void charEntered(const char*);
void charEntered(char);
void keyDown(int key, int modifiers = 0);
void keyUp(int key, int modifiers = 0);

View File

@ -116,7 +116,7 @@ void CelestialBrowser::slotRefresh()
{
char buf[20];
const Star *star=(Star *)(*i);
QString name((stardb->getStarName(*star)).c_str());
QString name = QString::fromUtf8((stardb->getStarName(*star)).c_str());
Point3f starPos = star->getPosition();
Vec3d v(starPos.x - obsPos.x,
@ -154,7 +154,7 @@ void CelestialBrowser::slotRefresh()
sprintf(buf, " %.2f au", starBodyDist / KM_PER_AU);
QString distStarBody(buf);
CelListViewItem *planetItem = new CelListViewItem(starItem, QString(body->getName().c_str()),
CelListViewItem *planetItem = new CelListViewItem(starItem, QString::fromUtf8(body->getName().c_str()),
distStarBody, "", "", getClassification(body->getClassification()));
const PlanetarySystem* satellites = body->getSatellites();
@ -171,7 +171,7 @@ void CelestialBrowser::slotRefresh()
QString distBodySat(buf);
new CelListViewItem(planetItem,
QString(sat->getName().c_str()),
QString::fromUtf8(sat->getName().c_str()),
distBodySat, "", "", getClassification(sat->getClassification()));
}

View File

@ -208,6 +208,25 @@ void KdeWatcher::notifyChange(CelestiaCore * core, int property)
kdeapp->resyncVerbosity();
else if (property & CelestiaCore::HistoryChanged)
kdeapp->resyncHistory();
if (property == CelestiaCore::TextEnterModeChanged) {
static std::vector<KAction*> actions;
if (kdeapp->appCore->getTextEnterMode() != CelestiaCore::KbNormal) {
for (unsigned int n=0; n < kdeapp->getActionCollection()->count(); n++) {
if (kdeapp->getActionCollection()->action(n)->shortcut().count() > 0
&& (kdeapp->getActionCollection()->action(n)->shortcut().seq(0).key(0).modFlags()
& (KKey::CTRL | KKey::ALT | KKey::WIN )) == 0 ) {
actions.push_back(kdeapp->getActionCollection()->action(n));
kdeapp->getActionCollection()->action(n)->setEnabled(false);
}
}
} else {
for (std::vector<KAction*>::iterator n=actions.begin(); n<actions.end(); n++) {
(*n)->setEnabled(true);
}
actions.clear();
}
}
}
void KdeApp::resyncHistory() {
@ -841,7 +860,7 @@ void KdeApp::slotPreferences() {
void KdeApp::slotSetTime() {
KdePreferencesDialog dlg(this, appCore);
dlg.showPage(1);
dlg.showPage(2);
dlg.exec();
}

View File

@ -82,6 +82,7 @@ public:
void openBookmarkURL(const QString& _url);
Url currentUrl(Url::UrlType type = Url::Absolute) const ;
QString currentIcon() const;
const KActionCollection* getActionCollection() { return actionCollection(); }
public slots:
void celestia_tick() { appCore->tick(); glWidget->updateGL(); }

View File

@ -383,18 +383,9 @@ bool KdeGlWidget::handleSpecialKey(QKeyEvent* e, bool down)
void KdeGlWidget::keyPressEvent( QKeyEvent* e )
{
static bool inputMode = false;
static std::vector<KAction*> actions;
switch (e->key())
{
case Key_Escape:
if (inputMode)
{
for (unsigned int n=0; n<actionColl->count(); n++) {
if (actionColl->action(n)->shortcut().seq(0).key(0).modFlags()==0)
actionColl->action(n)->setEnabled(true);
}
inputMode = !inputMode;
}
appCore->charEntered('\033');
break;
case Key_BackTab:
@ -408,38 +399,14 @@ void KdeGlWidget::keyPressEvent( QKeyEvent* e )
// Intentional fallthrough if *not* Ctrl-Q
default:
if (!handleSpecialKey(e, true))
if (appCore->getTextEnterMode() != CelestiaCore::KbNormal || !handleSpecialKey(e, true))
{
if ((e->text() != 0) && (e->text() != ""))
{
for (unsigned int i=0; i<e->text().length(); i++)
{
char c = e->text().at(i).latin1();
if (c == 0x0D || c=='\033') {
if (!inputMode) { // entering input mode
for (unsigned int n=0; n<actionColl->count(); n++) {
if (actionColl->action(n)->shortcut().count() > 0
&& (actionColl->action(n)->shortcut().seq(0).key(0).modFlags()
& (KKey::CTRL | KKey::ALT | KKey::WIN )) == 0 ) {
actions.push_back(actionColl->action(n));
actionColl->action(n)->setEnabled(false);
}
}
} else { // living input mode
for (std::vector<KAction*>::iterator n=actions.begin(); n<actions.end(); n++) {
(*n)->setEnabled(true);
}
actions.clear();
}
inputMode = !inputMode;
}
if (c >= 0x20 || c == 0x0D || c== 0x08 || c=='\011') appCore->charEntered(c);
}
appCore->charEntered(e->text().utf8().data());
}
}
}
}

View File

@ -552,6 +552,47 @@ int UTF8StringCompare(const std::string& s0, const std::string& s1)
return 0;
}
int UTF8StringCompare(const std::string& s0, const std::string& s1, size_t n)
{
int len0 = s0.length();
int len1 = s1.length();
int i0 = 0;
int i1 = 0;
while (i0 < len0 && i1 < len1 && n > 0)
{
wchar_t ch0 = 0;
wchar_t ch1 = 0;
if (!UTF8Decode(s0, i0, ch0))
return 1;
if (!UTF8Decode(s1, i1, ch1))
return -1;
i0 += UTF8EncodedSize(ch0);
i1 += UTF8EncodedSize(ch1);
ch0 = UTF8Normalize(ch0);
ch1 = UTF8Normalize(ch1);
if (ch0 < ch1)
return -1;
else if (ch0 > ch1)
return 1;
n--;
}
if (n == 0)
return 0;
len0 = UTF8Length(s0);
len1 = UTF8Length(s1);
if (len0 > len1)
return 1;
else if (len0 < len1)
return -1;
else
return 0;
}
// Currently incomplete, but could be a helpful class for dealing with
// UTF-8 streams

View File

@ -20,6 +20,7 @@ bool UTF8Decode(const std::string& str, int pos, wchar_t& ch);
bool UTF8Decode(const char* str, int pos, int length, wchar_t& ch);
int UTF8Encode(wchar_t ch, char* s);
int UTF8StringCompare(const std::string& s0, const std::string& s1);
int UTF8StringCompare(const std::string& s0, const std::string& s1, size_t length);
int UTF8Length(const std::string& s);
inline int UTF8EncodedSize(wchar_t ch)