~ubuntu-branches/ubuntu/oneiric/mozc/oneiric

« back to all changes in this revision

Viewing changes to unix/scim/scim_mozc.cc

  • Committer: Bazaar Package Importer
  • Author(s): Nobuhiro Iwamatsu
  • Date: 2010-07-14 03:26:47 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100714032647-13qjisj6m8cm8jdx
Tags: 0.12.410.102-1
* New upstream release (Closes: #588971).
  - Add mozc-server, mozc-utils-gui and scim-mozc packages.
* Update debian/rules.
  Add --gypdir option to build_mozc.py.
* Update debian/control.
  - Bumped standards-version to 3.9.0.
  - Update description.
* Add mozc icon (Closes: #588972).
* Add patch which revises issue 18.
  ibus_mozc_issue18.patch
* kFreeBSD build support.
  support_kfreebsd.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2010, Google Inc.
 
2
// All rights reserved.
 
3
//
 
4
// Redistribution and use in source and binary forms, with or without
 
5
// modification, are permitted provided that the following conditions are
 
6
// met:
 
7
//
 
8
//     * Redistributions of source code must retain the above copyright
 
9
// notice, this list of conditions and the following disclaimer.
 
10
//     * Redistributions in binary form must reproduce the above
 
11
// copyright notice, this list of conditions and the following disclaimer
 
12
// in the documentation and/or other materials provided with the
 
13
// distribution.
 
14
//     * Neither the name of Google Inc. nor the names of its
 
15
// contributors may be used to endorse or promote products derived from
 
16
// this software without specific prior written permission.
 
17
//
 
18
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
19
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
20
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
21
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
22
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
23
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
24
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
25
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
26
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
27
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
28
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
29
 
 
30
#include "unix/scim/scim_mozc.h"
 
31
 
 
32
#include <string>
 
33
 
 
34
#include "base/const.h"
 
35
#include "base/logging.h"
 
36
#include "base/process.h"
 
37
#include "base/util.h"
 
38
#include "unix/scim/mozc_connection.h"
 
39
#include "unix/scim/mozc_lookup_table.h"
 
40
#include "unix/scim/mozc_response_parser.h"
 
41
#include "unix/scim/scim_key_translator.h"
 
42
 
 
43
namespace {
 
44
 
 
45
const char kConfigName[] = "/Panel/Gtk/LookupTableVertical";
 
46
 
 
47
const char kPropTool[] = "/Mozc/Tool";
 
48
const char kPropToolIcon[] = SCIM_ICONDIR "/scim-mozc-tool.png";
 
49
const char kPropToolDictionary[] = "/Mozc/Tool/dictionary";
 
50
const char kPropToolDictionaryIcon[] = SCIM_ICONDIR "/scim-mozc-dictionary.png";
 
51
const char kPropToolProperty[] = "/Mozc/Tool/property";
 
52
const char kPropToolPropertyIcon[] = SCIM_ICONDIR "/scim-mozc-property.png";
 
53
 
 
54
const char kPropCompositionModeIcon[] = "/Mozc/CompositionMode";
 
55
 
 
56
const struct CompositionMode {
 
57
  const char *icon;
 
58
  const char *label;
 
59
  const char *config_path;
 
60
  const char *description;
 
61
  mozc::commands::CompositionMode mode;
 
62
} kPropCompositionModes[] = {
 
63
  {
 
64
    "",  // TODO(yusukes): use icons.
 
65
    "A",
 
66
    "/Mozc/CompositionMode/direct",
 
67
    "Direct",
 
68
    mozc::commands::DIRECT,
 
69
  }, {
 
70
    "",
 
71
    "\xe3\x81\x82",  // Hiragana letter A in UTF-8.
 
72
    "/Mozc/CompositionMode/hiragana",
 
73
    "Hiragana",
 
74
    mozc::commands::HIRAGANA,
 
75
  }, {
 
76
    "",
 
77
    "\xe3\x82\xa2",  // Katakana letter A.
 
78
    "/Mozc/CompositionMode/full_katakana",
 
79
    "Full Katakana",
 
80
    mozc::commands::FULL_KATAKANA,
 
81
  }, {
 
82
    "",
 
83
    "_A",
 
84
    "/Mozc/CompositionMode/half_ascii",
 
85
    "Half ASCII",
 
86
    mozc::commands::HALF_ASCII,
 
87
  }, {
 
88
    "",
 
89
    "\xef\xbc\xa1",  // Full width ASCII letter A.
 
90
    "/Mozc/CompositionMode/full_ascii",
 
91
    "Full ASCII",
 
92
    mozc::commands::FULL_ASCII,
 
93
  }, {
 
94
    "",
 
95
    "_\xef\xbd\xb1",  // Half width Katakana letter A.
 
96
    "/Mozc/CompositionMode/half_katakana",
 
97
    "Half Katakana",
 
98
    mozc::commands::HALF_KATAKANA,
 
99
  },
 
100
};
 
101
const size_t kNumCompositionModes = arraysize(kPropCompositionModes);
 
102
 
 
103
// This array must correspond with the CompositionMode enum in the
 
104
// mozc/session/command.proto file.
 
105
COMPILE_ASSERT(
 
106
    mozc::commands::NUM_OF_COMPOSITIONS == arraysize(kPropCompositionModes),
 
107
    bad_number_of_modes);
 
108
 
 
109
}  // namespace
 
110
 
 
111
namespace mozc_unix_scim {
 
112
 
 
113
/* static */
 
114
ScimMozc *ScimMozc::CreateScimMozc(scim::IMEngineFactoryBase *factory,
 
115
                                   const scim::String &encoding, int id,
 
116
                                   const scim::ConfigPointer *config) {
 
117
  return new ScimMozc(factory, encoding, id,
 
118
                      config,
 
119
                      MozcConnection::CreateMozcConnection(),
 
120
                      new MozcResponseParser);
 
121
}
 
122
 
 
123
// For unittests.
 
124
ScimMozc::ScimMozc(scim::IMEngineFactoryBase *factory,
 
125
                   const scim::String &encoding, int id,
 
126
                   const scim::ConfigPointer *config,
 
127
                   MozcConnectionInterface *connection,
 
128
                   MozcResponseParser *parser)
 
129
    : scim::IMEngineInstanceBase(factory, encoding, id),
 
130
      connection_(connection),
 
131
      parser_(parser),
 
132
      composition_mode_(mozc::commands::HIRAGANA) {
 
133
  VLOG(1) << "ScimMozc created.";
 
134
  const bool is_vertical
 
135
      = config ? (*config)->read(kConfigName, false) : false;
 
136
  parser_->set_use_annotation(is_vertical);
 
137
  InitializeBar();
 
138
}
 
139
 
 
140
ScimMozc::~ScimMozc() {
 
141
  VLOG(1) << "ScimMozc destroyed.";
 
142
}
 
143
 
 
144
// This function is called from SCIM framework when users press or release a
 
145
// key.
 
146
bool ScimMozc::process_key_event(const scim::KeyEvent &key) {
 
147
  VLOG(1) << "process_key_event, key.code=" << key.code;
 
148
 
 
149
  if (!connection_->CanSend(key)) {
 
150
    VLOG(1) << "Mozc doesn't handle the key. Not consumed.";
 
151
    return false;  // not consumed.
 
152
  }
 
153
 
 
154
  string error;
 
155
  mozc::commands::Output raw_response;
 
156
  if (!connection_->TrySendKeyEvent(
 
157
          key, composition_mode_, &raw_response, &error)) {
 
158
    // TODO(yusukes): Show |error|.
 
159
    return false;  // not consumed.
 
160
  }
 
161
 
 
162
  return ParseResponse(raw_response);
 
163
}
 
164
 
 
165
// This function is called from SCIM framework when users click the candidate
 
166
// window.
 
167
void ScimMozc::select_candidate(unsigned int index) {
 
168
  VLOG(1) << "select_candidate, index=" << index;
 
169
 
 
170
  if (!candidates_.get()) {
 
171
    LOG(ERROR) << "Candidate window clicked, but we don't have the instance.";
 
172
    return;
 
173
  }
 
174
 
 
175
  const int32 id = candidates_->GetId(index);
 
176
  if (id == kBadCandidateId) {
 
177
    LOG(ERROR) << "The clicked candidate doesn't have unique ID.";
 
178
    return;
 
179
  }
 
180
  VLOG(1) << "select_candidate, id=" << id;
 
181
 
 
182
  string error;
 
183
  mozc::commands::Output raw_response;
 
184
  if (!connection_->TrySendClick(id, &raw_response, &error)) {
 
185
    LOG(ERROR) << "IPC failed. error=" << error;
 
186
    SetAuxString(error);
 
187
    DrawAll();
 
188
  } else {
 
189
    ParseResponse(raw_response);
 
190
  }
 
191
}
 
192
 
 
193
// This function is called from SCIM framework.
 
194
void ScimMozc::reset() {
 
195
  VLOG(1) << "reset";
 
196
  string error;
 
197
  mozc::commands::Output raw_response;
 
198
  if (connection_->TrySendCommand(
 
199
          mozc::commands::SessionCommand::REVERT, &raw_response, &error)) {
 
200
    parser_->ParseResponse(raw_response, this);
 
201
  }
 
202
  ClearAll();  // just in case.
 
203
  DrawAll();
 
204
}
 
205
 
 
206
// This function is called from SCIM framework when the ic gets focus.
 
207
void ScimMozc::focus_in() {
 
208
  VLOG(1) << "focus_in";
 
209
  DrawAll();
 
210
  InitializeBar();
 
211
}
 
212
 
 
213
// This function is called when the ic loses focus.
 
214
void ScimMozc::focus_out() {
 
215
  VLOG(1) << "focus_out";
 
216
  string error;
 
217
  mozc::commands::Output raw_response;
 
218
  if (connection_->TrySendCommand(
 
219
          mozc::commands::SessionCommand::REVERT, &raw_response, &error)) {
 
220
    parser_->ParseResponse(raw_response, this);
 
221
  }
 
222
  ClearAll();  // just in case.
 
223
  DrawAll();
 
224
  // TODO(yusukes): Call session::SyncData() like ibus-mozc.
 
225
}
 
226
 
 
227
// This function is called from SCIM framework when Mozc related icon in the
 
228
// SCIM toolbar is pressed.
 
229
void ScimMozc::trigger_property(const scim::String &property) {
 
230
  VLOG(1) << "trigger_property: " << property;
 
231
 
 
232
  for (size_t i = 0; i < kNumCompositionModes; ++i) {
 
233
    if (property == kPropCompositionModes[i].config_path) {
 
234
      if (kPropCompositionModes[i].mode == mozc::commands::DIRECT) {
 
235
        // Commit a preedit string.
 
236
        string error;
 
237
        mozc::commands::Output raw_response;
 
238
        if (connection_->TrySendCommand(mozc::commands::SessionCommand::SUBMIT,
 
239
                                        &raw_response, &error)) {
 
240
          parser_->ParseResponse(raw_response, this);
 
241
        }
 
242
        DrawAll();
 
243
        // Switch to the DIRECT mode.
 
244
        SetCompositionMode(mozc::commands::DIRECT);
 
245
      } else {
 
246
        // Send the SWITCH_INPUT_MODE command.
 
247
        string error;
 
248
        mozc::commands::Output raw_response;
 
249
        if (connection_->TrySendCompositionMode(
 
250
                kPropCompositionModes[i].mode, &raw_response, &error)) {
 
251
          parser_->ParseResponse(raw_response, this);
 
252
        }
 
253
      }
 
254
      return;
 
255
    }
 
256
  }
 
257
 
 
258
  string args;
 
259
  if (property == kPropToolDictionary) {
 
260
    args = "--mode=dictionary_tool";
 
261
  } else if (property == kPropToolProperty) {
 
262
    args = "--mode=config_dialog";
 
263
  } else {
 
264
    // Unknown property.
 
265
    return;
 
266
  }
 
267
 
 
268
  // Spawn mozc_tool.
 
269
  // TODO(yusukes): Use session::LaunchTool().
 
270
  mozc::Process::SpawnMozcProcess("mozc_tool", args);
 
271
}
 
272
 
 
273
bool ScimMozc::ParseResponse(const mozc::commands::Output &raw_response) {
 
274
  ClearAll();
 
275
  const bool consumed = parser_->ParseResponse(raw_response, this);
 
276
  if (!consumed) {
 
277
    VLOG(1) << "The input was not consumed by Mozc.";
 
278
  }
 
279
  OpenUrl();
 
280
  DrawAll();
 
281
  return consumed;
 
282
}
 
283
 
 
284
void ScimMozc::SetResultString(const scim::WideString &result_string) {
 
285
  commit_string(result_string);
 
286
}
 
287
 
 
288
void ScimMozc::SetCandidateWindow(const MozcLookupTable *new_candidates) {
 
289
  candidates_.reset(new_candidates);
 
290
}
 
291
 
 
292
void ScimMozc::SetPreeditInfo(const PreeditInfo *preedit_info) {
 
293
  preedit_info_.reset(preedit_info);
 
294
}
 
295
 
 
296
void ScimMozc::SetAuxString(const scim::String &str) {
 
297
  aux_ = str;
 
298
}
 
299
 
 
300
void ScimMozc::SetCompositionMode(mozc::commands::CompositionMode mode) {
 
301
  composition_mode_ = mode;
 
302
  // Update the bar.
 
303
  const char *icon = GetCurrentCompositionModeIcon();
 
304
  const char *label = GetCurrentCompositionModeLabel();
 
305
  scim::Property p = scim::Property(
 
306
      kPropCompositionModeIcon, label, icon, "Composition mode");
 
307
  update_property(p);
 
308
}
 
309
 
 
310
void ScimMozc::SetUrl(const string &url) {
 
311
  url_ = url;
 
312
}
 
313
 
 
314
void ScimMozc::ClearAll() {
 
315
  SetCandidateWindow(NULL);
 
316
  SetPreeditInfo(NULL);
 
317
  SetAuxString("");
 
318
  url_.clear();
 
319
}
 
320
 
 
321
void ScimMozc::DrawCandidateWindow() {
 
322
  if (!candidates_.get()) {
 
323
    VLOG(1) << "HideCandidateWindow";
 
324
    hide_lookup_table();
 
325
  } else {
 
326
    VLOG(1) << "DrawCandidateWindow";
 
327
    update_lookup_table(*candidates_.get());
 
328
    show_lookup_table();
 
329
  }
 
330
}
 
331
 
 
332
void ScimMozc::DrawPreeditInfo() {
 
333
  if (!preedit_info_.get()) {
 
334
    hide_preedit_string();
 
335
  } else {
 
336
    VLOG(1) << "DrawPreeditInfo: cursor=" << preedit_info_->cursor_pos;
 
337
    update_preedit_string(preedit_info_->str,
 
338
                          preedit_info_->attribute_list);
 
339
    update_preedit_caret(preedit_info_->cursor_pos);
 
340
    show_preedit_string();
 
341
  }
 
342
}
 
343
 
 
344
void ScimMozc::DrawAux() {
 
345
  if (aux_.empty()) {
 
346
    hide_aux_string();
 
347
  } else {
 
348
    update_aux_string(scim::utf8_mbstowcs(aux_));
 
349
    show_aux_string();
 
350
  }
 
351
}
 
352
 
 
353
void ScimMozc::DrawAll() {
 
354
  DrawPreeditInfo();
 
355
  DrawAux();
 
356
  DrawCandidateWindow();
 
357
}
 
358
 
 
359
void ScimMozc::OpenUrl() {
 
360
  if (url_.empty()) {
 
361
    return;
 
362
  }
 
363
  mozc::Process::OpenBrowser(url_);
 
364
  url_.clear();
 
365
}
 
366
 
 
367
void ScimMozc::InitializeBar() {
 
368
  VLOG(1) << "Registering properties";
 
369
  // TODO(yusukes): L10N needed for "Tool", "Dictionary", and "Property".
 
370
  scim::PropertyList prop_list;
 
371
 
 
372
  const char *icon = GetCurrentCompositionModeIcon();
 
373
  const char *label = GetCurrentCompositionModeLabel();
 
374
  scim::Property p = scim::Property(
 
375
      kPropCompositionModeIcon, label, icon, "Composition mode");
 
376
  prop_list.push_back(p);
 
377
  for (size_t i = 0; i < kNumCompositionModes; ++i) {
 
378
    p = scim::Property(kPropCompositionModes[i].config_path,
 
379
                       kPropCompositionModes[i].description,
 
380
                       kPropCompositionModes[i].icon,
 
381
                       kPropCompositionModes[i].description);
 
382
    prop_list.push_back(p);
 
383
  }
 
384
 
 
385
  if (mozc::Util::FileExists(mozc::Util::JoinPath(
 
386
          mozc::Util::GetServerDirectory(), mozc::kMozcTool))) {
 
387
    // Construct "tool" icon and its menu.
 
388
    p = scim::Property(kPropTool, "", kPropToolIcon, "Tool");
 
389
    prop_list.push_back(p);
 
390
    p = scim::Property(
 
391
        kPropToolDictionary, "Dictionary", kPropToolDictionaryIcon);
 
392
    prop_list.push_back(p);
 
393
    p = scim::Property(kPropToolProperty, "Property", kPropToolPropertyIcon);
 
394
    prop_list.push_back(p);
 
395
  }
 
396
 
 
397
  register_properties(prop_list);
 
398
}
 
399
 
 
400
const char *ScimMozc::GetCurrentCompositionModeIcon() const {
 
401
  DCHECK(composition_mode_ < kNumCompositionModes);
 
402
  if (composition_mode_ < kNumCompositionModes) {
 
403
    return kPropCompositionModes[composition_mode_].icon;
 
404
  }
 
405
  return "";
 
406
}
 
407
 
 
408
const char *ScimMozc::GetCurrentCompositionModeLabel() const {
 
409
  DCHECK(composition_mode_ < kNumCompositionModes);
 
410
  if (composition_mode_ < kNumCompositionModes) {
 
411
    return kPropCompositionModes[composition_mode_].label;
 
412
  }
 
413
  return "";
 
414
}
 
415
 
 
416
}  // namespace mozc_unix_scim