[aquaskk-changes 130] CVS update: AquaSKK

Tomotaka SUWA t-suw****@users*****
2006年 2月 15日 (水) 00:12:44 JST


Index: AquaSKK/DMDictionary.cpp
diff -u AquaSKK/DMDictionary.cpp:1.4 AquaSKK/DMDictionary.cpp:1.4.2.1
--- AquaSKK/DMDictionary.cpp:1.4	Tue Nov 15 00:37:13 2005
+++ AquaSKK/DMDictionary.cpp	Wed Feb 15 00:12:44 2006
@@ -1,10 +1,10 @@
 /*
-  $Id: DMDictionary.cpp,v 1.4 2005/11/14 15:37:13 t-suwa Exp $
+  $Id: DMDictionary.cpp,v 1.4.2.1 2006/02/14 15:12:44 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
   Copyright (C) 2002 phonohawk
-  Copyright (C) 2005 Tomotaka SUWA <t.suw****@mac*****>
+  Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****>
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -35,9 +35,8 @@
 
 static OSErr FilePathToFSSpec(CFStringRef filePath, FSSpec* apSpec);
 
-DMDictionary::KotoeriDictionary::KotoeriDictionary(const CFStringRef path)
-    : path_(0), isRegistered_(false), id_(0) {
-    path_ = CFStringCreateCopy(kCFAllocatorDefault, path);
+KotoeriDictionary::KotoeriDictionary(const std::string path) : path_(0), isRegistered_(false), id_(0) {
+    path_ = CFStringCreateWithCString(kCFAllocatorDefault, path.c_str(), kCFStringEncodingEUC_JP);
     if(!path_) {
 	std::cerr << "KotoeriDictionary: CFStringCreateCopy() failed" << std::endl;
 	return;
@@ -56,9 +55,16 @@
 	}
 	isRegistered_ = true;
     }
+
+    char buf[1024];
+    CFStringGetCString(path_, buf, sizeof(buf), kCFStringEncodingUTF8);
+    std::cerr << "Kotoeri Dictionary(" << buf << ")" << std::endl
+	      << "  okuri-ari: 0 entries." << std::endl
+	      << "  okuri-nasi: " << countOkuriNasi() << " entries."
+	      << std::endl << std::endl;
 }
 
-DMDictionary::KotoeriDictionary::~KotoeriDictionary() {
+KotoeriDictionary::~KotoeriDictionary() {
     if(isRegistered_) {
 	DCMUnregisterDictionary(id_);
     }
@@ -68,38 +74,11 @@
     }
 }
 
-bool DMDictionary::KotoeriDictionary::Find(const CFStringRef key,
-					   DCMFoundRecordIterator* iterator) {
-    DCMDictionaryRef ref;
-    if(DCMOpenDictionary(id_, 0, NULL, &ref) != noErr) {
-	std::cerr << "DCMOpenDictionary() failed" << std::endl;
-	return false;
-    }
-
-    // ƒŒƒR[ƒh‚ðŒŸõ
-    OSStatus status;
-    DCMFieldTag	dataFieldTagList[] = { kDCMJapaneseHyokiTag };
-    ByteCount length = CFStringGetLength(key) * sizeof(UniChar);
-    status = DCMFindRecords(ref, // Dictionary reference
-			    kDCMJapaneseYomiTag, // key field tag
-			    length,		 // key data length
-			    CFStringGetCharactersPtr(key), // key data
-			    kDCMFindMethodExactMatch, // find method
-			    1,		      // number of data field
-			    dataFieldTagList, // data field tag list
-			    0, 0, // search all records
-			    iterator); // found result
-
-    DCMCloseDictionary(ref);
-
-    return (status == noErr);
-}
-
-const bool DMDictionary::KotoeriDictionary::IsGood() const {
-    return (id_ != 0);
+int KotoeriDictionary::countOkuriAri() {
+    return 0;
 }
 
-const int DMDictionary::KotoeriDictionary::Count() const {
+int KotoeriDictionary::countOkuriNasi() {
     ItemCount numItems;
     if(DCMCountRecord(id_, &numItems) == noErr) {
 	return numItems;
@@ -108,145 +87,96 @@
     return 0;
 }
 
-const void DMDictionary::KotoeriDictionary::Description() const {
-    char buf[1024];
-    CFStringGetCString(path_, buf, sizeof(buf), kCFStringEncodingUTF8);
-    std::cerr << "Kotoeri Dictionary(" << buf << ")" << std::endl
-	      << "  okuri-ari: 0 entries." << std::endl
-	      << "  okuri-nasi: " << Count() << " entries."
-	      << std::endl << std::endl;
-}
-
-// ------------------------------------------------------------------
-
-DMDictionary::DMDictionary(const std::vector<CppCFString>& kotoeri_dic_file) {
-    load(kotoeri_dic_file);
-}
-
-DMDictionary::~DMDictionary() {
-    unload();
-}
-
-int DMDictionary::countOkuriAri() {
-    return 0;
-}
-
-int DMDictionary::countOkuriNasi() {
-    int result = 0;
-
-    for(KotoeriDictionaryIterator i = dics_.begin(); i != dics_.end(); ++ i) {
-	result += (*i)->Count();
-    }
-
-    return result;
-}
-
-std::vector<OkuriganaEntry> DMDictionary::findOkuriAri(const CppCFString& str) {
+std::vector<OkuriganaEntry> KotoeriDictionary::findOkuriAri(const CppCFString& str) {
     // ‚±‚Æ‚¦‚莫‘‚ɂ́u‘—‚è‚ ‚èv‚Í‘¶Ý‚µ‚È‚¢
     return std::vector<OkuriganaEntry>();
 }
 
-std::vector<CppCFString> DMDictionary::findOkuriNasi(const CppCFString& str) {
+std::vector<CppCFString> KotoeriDictionary::findOkuriNasi(const CppCFString& str) {
     OSStatus status;
     std::vector<CppCFString> result;
 
-    for(KotoeriDictionaryIterator i = dics_.begin(); i != dics_.end(); ++ i) {
-	DCMFoundRecordIterator iterator;
-	if(!(*i)->Find(str.getString(), &iterator)) continue;
-
-        while(true) {
-            ByteCount keySize;
-            char foundKeyStr[kMaxKanjiLengthInAppleJapaneseDictionary];
-            DCMUniqueID uniqueID;
-            AERecord dataList;
-            
-            // Get one record from result list
-            status = DCMIterateFoundRecord(iterator, // found result
-					   kMaxKanjiLengthInAppleJapaneseDictionary, // key buffer size
-					   &keySize, // actual found key size
-					   foundKeyStr, // found key data
-					   &uniqueID,	 // ƒ†ƒj[ƒNID
-					   &dataList);	// AERecordƒf[ƒ^
-
-            if(status != noErr) break;
-    
-            DescType actualType;
-            char dataBuffer[kMaxKanjiLengthInAppleJapaneseDictionary];
-            Size actualSize;
-
-            // Get one data from AERecord
-            status = AEGetKeyPtr(&dataList, 
-				 kDCMJapaneseHyokiTag,
-				 'utxt',
-				 &actualType,
-				 dataBuffer,
-				 kMaxKanjiLengthInAppleJapaneseDictionary,
-				 &actualSize);
-
-            // Dispose data AERecord
-            AEDisposeDesc(&dataList);
-
-	    if(status != noErr) break;
-
-	    // Œ‹‰Ê‚ɒljÁ‚·‚é
-	    result.push_back(CppCFData(dataBuffer, actualSize).getData());
-        }
-	DCMDisposeRecordIterator(iterator);
+    DCMFoundRecordIterator iterator;
+    if(!find(str.getString(), &iterator)) {
+	return result;
+    }
+
+    while(true) {
+	ByteCount keySize;
+	char foundKeyStr[kMaxKanjiLengthInAppleJapaneseDictionary];
+	DCMUniqueID uniqueID;
+	AERecord dataList;
+
+	// Get one record from result list
+	status = DCMIterateFoundRecord(iterator, // found result
+				       kMaxKanjiLengthInAppleJapaneseDictionary, // key buffer size
+				       &keySize, // actual found key size
+				       foundKeyStr, // found key data
+				       &uniqueID,   // ƒ†ƒj[ƒNID
+				       &dataList);  // AERecordƒf[ƒ^
+
+	if(status != noErr) break;
+
+	DescType actualType;
+	char dataBuffer[kMaxKanjiLengthInAppleJapaneseDictionary];
+	Size actualSize;
+
+	// Get one data from AERecord
+	status = AEGetKeyPtr(&dataList, 
+			     kDCMJapaneseHyokiTag,
+			     'utxt',
+			     &actualType,
+			     dataBuffer,
+			     kMaxKanjiLengthInAppleJapaneseDictionary,
+			     &actualSize);
+
+	// Dispose data AERecord
+	AEDisposeDesc(&dataList);
+
+	if(status != noErr) break;
+
+	// Œ‹‰Ê‚ɒljÁ‚·‚é
+	result.push_back(CppCFData(dataBuffer, actualSize).getData());
     }
+    DCMDisposeRecordIterator(iterator);
 
     return result;
 }
 
-void DMDictionary::changeDictionaryFile(const std::vector<CppCFString>& dics) {
-    unload();
-    load(dics);
-}
-
-bool DMDictionary::checkDictionary(const CFStringRef path) {
-    return KotoeriDictionary(path).IsGood();
-}
-
-// ------------------------------------------------------------------
-
-void DMDictionary::load(const std::vector<CppCFString>& dics) {
-    for(std::vector<CppCFString>::const_iterator ite = dics.begin();
-	ite != dics.end(); ++ ite) {
-	KotoeriDictionary* dic = new KotoeriDictionary(ite->getString());
-        if(dic->IsGood()) {
-	    dics_.push_back(dic);
-	    dic->Description();
-	} else {
-	    delete dic;
-	}
+bool KotoeriDictionary::find(const CFStringRef key, DCMFoundRecordIterator* iterator) {
+    DCMDictionaryRef ref;
+    if(DCMOpenDictionary(id_, 0, NULL, &ref) != noErr) {
+	std::cerr << "DCMOpenDictionary() failed" << std::endl;
+	return false;
     }
-}
 
-void DMDictionary::unload() {
-    struct local {
-	static void DeleteObject(const KotoeriDictionary* ptr) {
-	    delete ptr;
-	}
-    };
-    std::for_each(dics_.begin(), dics_.end(), local::DeleteObject);
-    dics_.clear();
+    // ƒŒƒR[ƒh‚ðŒŸõ
+    OSStatus status;
+    DCMFieldTag	dataFieldTagList[] = { kDCMJapaneseHyokiTag };
+    ByteCount length = CFStringGetLength(key) * sizeof(UniChar);
+    status = DCMFindRecords(ref, // Dictionary reference
+			    kDCMJapaneseYomiTag, // key field tag
+			    length,		 // key data length
+			    CFStringGetCharactersPtr(key), // key data
+			    kDCMFindMethodExactMatch, // find method
+			    1,		      // number of data field
+			    dataFieldTagList, // data field tag list
+			    0, 0, // search all records
+			    iterator); // found result
+
+    DCMCloseDictionary(ref);
+
+    return (status == noErr);
 }
 
 static OSErr FilePathToFSSpec(CFStringRef filePath, FSSpec* apSpec) {
     FSRef fileRef;
     OSErr err = !noErr;
-    CFURLRef cfUrl = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, 
-						   filePath,
-						   kCFURLPOSIXPathStyle,
-						   false);
-    if(CFURLGetFSRef(cfUrl, &fileRef)) {
-        err = FSGetCatalogInfo(&fileRef,
-			       kFSCatInfoNone,
-			       NULL,
-			       NULL,
-			       apSpec,
-			       NULL);
+    CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, filePath, kCFURLPOSIXPathStyle, false);
+    if(CFURLGetFSRef(url, &fileRef)) {
+        err = FSGetCatalogInfo(&fileRef, kFSCatInfoNone, NULL, NULL, apSpec, NULL);
     }
-    CFRelease(cfUrl);
+    if(url) CFRelease(url);
 
     return err;
 }
Index: AquaSKK/DMDictionary.h
diff -u AquaSKK/DMDictionary.h:1.4 AquaSKK/DMDictionary.h:1.4.2.1
--- AquaSKK/DMDictionary.h:1.4	Tue Nov 15 00:37:13 2005
+++ AquaSKK/DMDictionary.h	Wed Feb 15 00:12:44 2006
@@ -1,10 +1,10 @@
 /*
-  $Id: DMDictionary.h,v 1.4 2005/11/14 15:37:13 t-suwa Exp $
+  $Id: DMDictionary.h,v 1.4.2.1 2006/02/14 15:12:44 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
   Copyright (C) 2002 phonohawk
-  Copyright (C) 2005 Tomotaka SUWA <t.suw****@mac*****>
+  Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****>
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -32,37 +32,19 @@
 class OkuriganaEntry;
 class CppCFString;
 
-class DMDictionary: public Dictionary {
-    class KotoeriDictionary {
-	CFStringRef path_;
-	bool isRegistered_;
-	DCMDictionaryID id_;
-
-    public:
-	KotoeriDictionary(const CFStringRef path);
-	~KotoeriDictionary();
-
-	bool Find(const CFStringRef key, DCMFoundRecordIterator* iterator);
-	const bool IsGood() const;
-	const int Count() const;
-	const void Description() const;
-    };
-    typedef std::vector<KotoeriDictionary*> KotoeriDictionaryContainer;
-    typedef KotoeriDictionaryContainer::iterator KotoeriDictionaryIterator;
-    KotoeriDictionaryContainer dics_;
+class KotoeriDictionary: public Dictionary {
+    CFStringRef path_;
+    bool isRegistered_;
+    DCMDictionaryID id_;
 
-    void load(const std::vector<CppCFString>& dicFiles);
-    void unload();
+    bool find(const CFStringRef key, DCMFoundRecordIterator* iterator);
 
 public:
-    DMDictionary(const std::vector<CppCFString>& kotoeri_dic_file);
-    virtual ~DMDictionary();
+    KotoeriDictionary(const std::string path);
+    virtual ~KotoeriDictionary();
 
     virtual int countOkuriAri();
     virtual int countOkuriNasi();
-    virtual std::vector<OkuriganaEntry> findOkuriAri(const CppCFString& root);
-    virtual std::vector<CppCFString> findOkuriNasi(const CppCFString& query);
-
-    void changeDictionaryFile(const std::vector<CppCFString>& kotoeri_dic_file);
-    bool checkDictionary(const CFStringRef fpath);
+    virtual std::vector<OkuriganaEntry> findOkuriAri(const CppCFString& str);
+    virtual std::vector<CppCFString> findOkuriNasi(const CppCFString& str);
 };
Index: AquaSKK/DictArrayController.h
diff -u /dev/null AquaSKK/DictArrayController.h:1.1.2.1
--- /dev/null	Wed Feb 15 00:12:44 2006
+++ AquaSKK/DictArrayController.h	Wed Feb 15 00:12:44 2006
@@ -0,0 +1,42 @@
+/* -*- objc -*-
+  $Id: DictArrayController.h,v 1.1.2.1 2006/02/14 15:12:44 t-suwa Exp $
+
+  MacOS X implementation of the SKK input method.
+
+  Copyright (C) 2006 Tomotaka SUWA <t.suw****@mac*****>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#import <Cocoa/Cocoa.h>
+
+ @ interface DictArrayController : NSArrayController
+{
+    IBOutlet NSWindow* prefView;
+    IBOutlet NSTableView* tableView;
+}
+
+- (IBAction)browseLocation:(id)sender;
+- (BOOL)tableView:(NSTableView *)tableView writeRows:(NSArray*)rows toPasteboard:(NSPasteboard*)pboard;
+- (NSDragOperation)tableView:(NSTableView*)tableView
+		validateDrop:(id <NSDraggingInfo>)info
+		 proposedRow:(int)row
+       proposedDropOperation:(NSTableViewDropOperation)op;
+- (BOOL)tableView:(NSTableView*)tableView
+       acceptDrop:(id <NSDraggingInfo>)info
+	      row:(int)row
+    dropOperation:(NSTableViewDropOperation)op;
+
+ @ end
Index: AquaSKK/DictArrayController.m
diff -u /dev/null AquaSKK/DictArrayController.m:1.1.2.1
--- /dev/null	Wed Feb 15 00:12:44 2006
+++ AquaSKK/DictArrayController.m	Wed Feb 15 00:12:44 2006
@@ -0,0 +1,170 @@
+/* -*- objc -*-
+  $Id: DictArrayController.m,v 1.1.2.1 2006/02/14 15:12:44 t-suwa Exp $
+
+  MacOS X implementation of the SKK input method.
+
+  Copyright (C) 2006 Tomotaka SUWA <t.suw****@mac*****>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#import "DictArrayController.h"
+
+// ドラッグ & ドロップ用
+static NSString* DictionaryRowsType = @"DictionaryRowsType";
+
+// 辞書テーブル用
+static NSString* DictActiveKey = @"active";
+static NSString* DictTypeKey = @"type";
+static NSString* DictLocationKey = @"location";
+
+ @ implementation DictArrayController
+
+- (void)moveObjectsInArrangedObjectsFromIndexes:(NSIndexSet*)indexSet toIndex:(unsigned int)insertIndex {
+    NSArray* objects = [self arrangedObjects];
+    unsigned int idx = [indexSet lastIndex];
+    int aboveInsertIndexCount = 0;
+    int removeIndex;
+
+    while(NSNotFound != idx) {
+	if(idx >= insertIndex) {
+	    removeIndex = idx + aboveInsertIndexCount;
+	    aboveInsertIndexCount += 1;
+	} else {
+	    removeIndex = idx;
+	    insertIndex -= 1;
+	}
+
+	id object = [[objects objectAtIndex:removeIndex] retain];
+	[self removeObjectAtArrangedObjectIndex:removeIndex];
+	[self insertObject:object atArrangedObjectIndex:insertIndex];
+	[object release];
+
+	idx = [indexSet indexLessThanIndex:idx];
+    }
+}
+
+- (NSIndexSet *)indexSetFromRows:(NSArray*)rows {
+    NSMutableIndexSet* indexSet = [NSMutableIndexSet indexSet];
+    NSEnumerator* rowEnumerator = [rows objectEnumerator];
+    NSNumber* idx;
+
+    while((idx = [rowEnumerator nextObject])) {
+	[indexSet addIndex:[idx intValue]];
+    }
+
+    return indexSet;
+}
+
+- (int)rowsAboveRow:(int)row inIndexSet:(NSIndexSet*)indexSet {
+    int currentIndex = [indexSet firstIndex];
+    int i = 0;
+
+    while(currentIndex != NSNotFound) {
+	if(currentIndex < row) {
+	    ++ i;
+	}
+	currentIndex = [indexSet indexGreaterThanIndex:currentIndex];
+    }
+
+    return i;
+}
+
+- (void)awakeFromNib {
+    [tableView registerForDraggedTypes:[NSArray arrayWithObjects:DictionaryRowsType, nil]];
+    [super awakeFromNib];
+}
+
+- (id)newObject {
+    id obj = [super newObject];
+
+    // 新規のエントリを初期化する
+    if(obj) {
+	[obj setValue:[NSNumber numberWithBool:YES] forKey:DictActiveKey];
+	[obj setValue:[NSNumber numberWithInt:10] forKey:DictTypeKey];
+	[obj setValue:@"" forKey:DictLocationKey];
+    }
+
+    return obj;
+}
+
+- (IBAction)browseLocation:(id)sender {
+    NSOpenPanel* panel = [NSOpenPanel openPanel];
+
+    [panel beginSheetForDirectory:nil file:nil types:nil modalForWindow:prefView modalDelegate:self
+	   didEndSelector:@selector(browsePanelDidEnd:returnCode:contextInfo:) contextInfo:nil];
+}
+
+- (void)browsePanelDidEnd:(NSOpenPanel*)openPanel returnCode:(int)returnCode contextInfo:(void*)contextInfo {
+    if(returnCode != NSOKButton) {
+	return;
+    }
+
+    [[self selection] setValue:[openPanel filename] forKey:DictLocationKey];
+}
+
+- (BOOL)tableView:(NSTableView *)tableView writeRows:(NSArray*)rows toPasteboard:(NSPasteboard*)pboard {
+    NSArray* typesArray = [NSArray arrayWithObjects:DictionaryRowsType, nil];
+
+    [pboard declareTypes:typesArray owner:self];
+    [pboard setPropertyList:rows forType:DictionaryRowsType];
+
+    return YES;
+}
+
+- (NSDragOperation)tableView:(NSTableView*)tv
+		validateDrop:(id <NSDraggingInfo>)info
+		 proposedRow:(int)row
+       proposedDropOperation:(NSTableViewDropOperation)op {
+    NSDragOperation dragOp = NSDragOperationCopy;
+
+    // ドラッグ元が同じなら、移動
+    if([info draggingSource] == tableView) {
+	dragOp =  NSDragOperationMove;
+    }
+
+    [tv setDropRow:row dropOperation:NSTableViewDropAbove];
+
+    return dragOp;
+}
+
+- (BOOL)tableView:(NSTableView*)tv
+       acceptDrop:(id <NSDraggingInfo>)info
+	      row:(int)row
+    dropOperation:(NSTableViewDropOperation)op {
+    if(row < 0) {
+	row = 0;
+    }
+
+    // ドラッグ元以外なら、何もしない
+    if([info draggingSource] != tableView) {
+	return NO;
+    }
+
+    NSArray* rows = [[info draggingPasteboard] propertyListForType:DictionaryRowsType];
+    NSIndexSet* indexSet = [self indexSetFromRows:rows];
+
+    [self moveObjectsInArrangedObjectsFromIndexes:indexSet toIndex:row];
+
+    int rowsAbove = [self rowsAboveRow:row inIndexSet:indexSet];
+		
+    NSRange range = NSMakeRange(row - rowsAbove, [indexSet count]);
+    indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
+    [self setSelectionIndexes:indexSet];
+		
+    return YES;
+}
+
+ @ end
Index: AquaSKK/Dictionary.h
diff -u AquaSKK/Dictionary.h:1.3.2.1 AquaSKK/Dictionary.h:1.3.2.2
--- AquaSKK/Dictionary.h:1.3.2.1	Sun Jan  8 16:15:30 2006
+++ AquaSKK/Dictionary.h	Wed Feb 15 00:12:44 2006
@@ -1,5 +1,5 @@
 /*
-  $Id: Dictionary.h,v 1.3.2.1 2006/01/08 07:15:30 t-suwa Exp $
+  $Id: Dictionary.h,v 1.3.2.2 2006/02/14 15:12:44 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
@@ -40,10 +40,8 @@
     virtual int countOkuriNasi() = 0;
 
     // ŒŸõ
-    virtual std::vector<OkuriganaEntry>
-	findOkuriAri(const CppCFString& query) = 0;
-    virtual std::vector<CppCFString>
-	findOkuriNasi(const CppCFString& query) = 0;
+    virtual std::vector<OkuriganaEntry> findOkuriAri(const CppCFString& query) = 0;
+    virtual std::vector<CppCFString> findOkuriNasi(const CppCFString& query) = 0;
 };
 
 // ’ŠÛƒ†[ƒU[Ž«‘ƒNƒ‰ƒX
@@ -52,21 +50,15 @@
     virtual ~UserDictionary() {};
 
     // Œ©o‚µŒê‚̕⊮
-    virtual std::vector<CppCFString>
-	findCompletions(const CppCFString& query) = 0;
+    virtual std::vector<CppCFString> findCompletions(const CppCFString& query) = 0;
 
     // ’PŒê“o˜^
-    virtual void registerOkuriAri(const CppCFString& index,
-				  const CppCFString& okuri,
-				  const CppCFString& kanji) = 0;
-    virtual void registerOkuriNasi(const CppCFString& index,
-				   const CppCFString& kanji) = 0;
+    virtual void registerOkuriAri(const CppCFString& index, const CppCFString& okuri, const CppCFString& kanji) = 0;
+    virtual void registerOkuriNasi(const CppCFString& index, const CppCFString& kanji) = 0;
 
     // ’PŒêíœ
-    virtual void removeOkuriAri(const CppCFString& index,
-				const CppCFString& kanji) = 0;
-    virtual void removeOkuriNasi(const CppCFString& index,
-				 const CppCFString& kanji) = 0;
+    virtual void removeOkuriAri(const CppCFString& index, const CppCFString& kanji) = 0;
+    virtual void removeOkuriNasi(const CppCFString& index, const CppCFString& kanji) = 0;
 };
 
 // ƒIƒuƒWƒFƒNƒg‚ð˜AŒ‹‚·‚éƒtƒ@ƒ“ƒNƒ^
Index: AquaSKK/Foundation.mm
diff -u AquaSKK/Foundation.mm:1.3.2.1 AquaSKK/Foundation.mm:1.3.2.2
--- AquaSKK/Foundation.mm:1.3.2.1	Sat Jan 14 20:01:58 2006
+++ AquaSKK/Foundation.mm	Wed Feb 15 00:12:44 2006
@@ -1,5 +1,5 @@
 /* -*- objc -*-
-  $Id: Foundation.mm,v 1.3.2.1 2006/01/14 11:01:58 t-suwa Exp $
+  $Id: Foundation.mm,v 1.3.2.2 2006/02/14 15:12:44 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
@@ -21,37 +21,22 @@
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-#import <AppKit/AppKit.h>
-#import "Foundation.h"
-#import "PreferencesController.h"
-
-#include <Carbon/Carbon.h>
-#include <vector>
+#include <AppKit/AppKit.h>
+#include "Foundation.h"
+#include "PreferencesController.h"
+#include "SKKServer.h"
 #include "BIMClientServer.h"
-#include "CppCFString.h"
-#include "CppCFData.h"
-#include "PrivateRunLoop.h"
-#include "CppMessagePortServer.h"
 #include "ServerMessageReceiver.h"
-#include "SKKServer.h"
-#include "net/Socket.h"
 #include "Skkserv.h"
 
 @implementation Foundation
 
 - (void)applicationDidFinishLaunching:(NSNotification*)aNotification {
-    // ‚±‚Æ‚¦‚莫‘‚̃pƒX‚ðŽæ“¾
+    // ƒvƒŠƒtƒ@ƒŒƒ“ƒX‚ðŽæ“¾
     PreferencesController* pref = [PreferencesController sharedController];
-    std::vector<CppCFString> vec;
-    for(unsigned i = 0 ; i < [[pref path] count] ; ++ i) {
-	vec.push_back((CFStringRef)[[pref path] objectAtIndex:i]);
-    }
 
     // Ž«‘ƒT[ƒo[‚ð‹N“®‚·‚é
-    SKKServer::sharedServer([[pref getPathToMainDic] cString],
-			    [[pref getPathToSubDic] cString],
-			    [[pref getPathToUserDic] cString],
-			    vec);
+    SKKServer::sharedServer();
 
     // ƒƒbƒZ[ƒWƒnƒ“ƒhƒ‰‚ð‹N“®‚·‚é
     ServerMessageReceiver::start(kAquaSKKServerRunLoopMode);
Index: AquaSKK/PreferencesController.h
diff -u AquaSKK/PreferencesController.h:1.6.2.2 AquaSKK/PreferencesController.h:1.6.2.3
--- AquaSKK/PreferencesController.h:1.6.2.2	Sun Jan  8 16:15:30 2006
+++ AquaSKK/PreferencesController.h	Wed Feb 15 00:12:44 2006
@@ -1,5 +1,5 @@
 /* -*- objc -*-
-  $Id: PreferencesController.h,v 1.6.2.2 2006/01/08 07:15:30 t-suwa Exp $
+  $Id: PreferencesController.h,v 1.6.2.3 2006/02/14 15:12:44 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
@@ -39,32 +39,16 @@
     IBOutlet id winColor;
     IBOutlet id winTransparent;
 
-    // SKK Ž«‘
-    IBOutlet NSTextField *maindic_path;
-    IBOutlet NSTextField *subdic_path;
-
-    // ‚±‚Æ‚¦‚莫‘
-    IBOutlet id addKotoeriBtn;
-    IBOutlet id kotoeriDicTable;
-    IBOutlet id removeKotoeriBtn;
-
     // skkserv
     IBOutlet NSButton *skkserv_enabled;
     IBOutlet NSTextField *skkserv_port;
     IBOutlet NSButton *skkserv_local_only;
 
-    NSString* path_to_main_dic;
-    NSString* path_to_sub_dic;
-    NSMutableArray *dicPath;
-
     NSFont *font;
     NSFontPanel* fontPanel;
     NSMenu* kbdLayoutMenu;
 }
 + (PreferencesController*)sharedController;
-- (NSString*)getPathToMainDic;
-- (NSString*)getPathToSubDic;
-- (NSString*)getPathToUserDic;
 
 - init;
 
@@ -84,15 +68,7 @@
 - (BOOL)isAsciiModeStartup;
 - (IBAction)asciiModeStartup:(id)sender;
 
-- (NSArray *)path;
-
-- (IBAction)selectMainDic:(id)sender;
-- (IBAction)selectSubDic:(id)sender;
-
-- (IBAction)addKotoeriDic:(id)sender;
-- (IBAction)removeKotoeriDic:(id)sender;
 - (IBAction)saveUserDefault:(id)sender;
-- (void)controlSetting;
 
 - (BOOL)isSkkservEnabled;
 - (int)skkservPort;
Index: AquaSKK/PreferencesController.mm
diff -u AquaSKK/PreferencesController.mm:1.6.2.4 AquaSKK/PreferencesController.mm:1.6.2.5
--- AquaSKK/PreferencesController.mm:1.6.2.4	Sat Jan 14 20:01:58 2006
+++ AquaSKK/PreferencesController.mm	Wed Feb 15 00:12:44 2006
@@ -1,5 +1,5 @@
 /*  -*- objc -*-
-  $Id: PreferencesController.mm,v 1.6.2.4 2006/01/14 11:01:58 t-suwa Exp $
+  $Id: PreferencesController.mm,v 1.6.2.5 2006/02/14 15:12:44 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
@@ -47,11 +47,6 @@
 static NSString* WindowAlphaKey = @"dic.WindowAlpha.kotoeri";
 static NSString* ShowCandsLimitKey = @"dic.showCandsWindowAfterNthCand";
 
-static NSString* MainDictPathKey = @"dic.path.main";
-static NSString* SubDictPathKey = @"dic.path.sub";
-
-static NSString* KotoeriDictPathKey = @"dic.path.kotoeri";
-
 static NSString* SKKServEnabledKey = @"pref.skkserv.enabled";
 static NSString* SKKServPortKey = @"pref.skkserv.port";
 static NSString* SKKServLocalOnlyKey = @"pref.skkserv.local-only";
@@ -167,9 +162,6 @@
     [templateDefaults setObject:[NSArchiver archivedDataWithRootObject:color] forKey:WindowColorKey];
     [templateDefaults setObject:@"1.0" forKey:WindowAlphaKey];
     [templateDefaults setObject:@"5" forKey:ShowCandsLimitKey];
-    [templateDefaults setObject:@"~/Library/AquaSKK/SKK-JISYO.L" forKey:MainDictPathKey];
-    [templateDefaults setObject:@"~/.skk-jisyo" forKey:SubDictPathKey];
-    [templateDefaults setObject:[NSMutableArray array] forKey:KotoeriDictPathKey];
     [templateDefaults setObject:@"NO" forKey:SKKServEnabledKey];
     [templateDefaults setObject:@"1178" forKey:SKKServPortKey];
     [templateDefaults setObject:@"YES" forKey:SKKServLocalOnlyKey];
@@ -195,12 +187,7 @@
     [winColor setColor:[NSUnarchiver unarchiveObjectWithData:[defaults objectForKey:WindowColorKey]]];
     [winTransparent setDoubleValue:[defaults floatForKey:WindowAlphaKey]];
 
-    // SKK Ž«‘
-    path_to_main_dic = [[NSString alloc] initWithString:[defaults stringForKey:MainDictPathKey]];
-    path_to_sub_dic = [[NSString alloc] initWithString:[defaults stringForKey:SubDictPathKey]];
-
-    // ‚±‚Æ‚¦‚莫‘
-    dicPath = [[NSMutableArray alloc] initWithArray:[defaults arrayForKey:KotoeriDictPathKey]];
+    // Ž«‘
 
     // skkserv
     [skkserv_enabled setState:[defaults boolForKey:SKKServEnabledKey]];
@@ -225,10 +212,7 @@
     [defaults setObject:[NSArchiver archivedDataWithRootObject:[winColor color]] forKey:WindowColorKey];
     [defaults setFloat:[winTransparent doubleValue] forKey:WindowAlphaKey];
 
-    // SKK Ž«‘
-
-    // ‚±‚Æ‚¦‚莫‘
-    [defaults setObject:dicPath forKey:KotoeriDictPathKey];
+    // Ž«‘
 
     // skkserv
     [defaults setBool:[skkserv_enabled state] forKey:SKKServEnabledKey];
@@ -302,24 +286,7 @@
     [self setState:kBasicMessageIsAsciiModeStartup state:[sender state]];
 }
 
-// SKKŽ«‘
-
-- (NSString*)getPathToMainDic {
-    return [path_to_main_dic stringByExpandingTildeInPath];
-}
-
-- (NSString*)getPathToSubDic {
-    return [path_to_sub_dic stringByExpandingTildeInPath];
-}
-
-- (NSString*)getPathToUserDic {
-    return [@"~/Library/AquaSKK/skk-user-dic" stringByExpandingTildeInPath];
-}
-
 - (IBAction)showWindow:(id)sender {
-    [maindic_path setStringValue:path_to_main_dic];
-    [subdic_path setStringValue:path_to_sub_dic];
-
     [NSApp activateIgnoringOtherApps:YES];
     [[self window] makeKeyAndOrderFront:nil];
 
@@ -329,32 +296,8 @@
 - (BOOL)windowShouldClose:(NSNotification *)aNotification {
     NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
 
-    if(![[[maindic_path stringValue] stringByAbbreviatingWithTildeInPath] isEqualToString:path_to_main_dic]) {
-	// ƒƒCƒ“Ž«‘‚̏ꏊ‚ª•Ï‚í‚Á‚½
-	[path_to_main_dic release];
-	path_to_main_dic = [[[maindic_path stringValue] stringByAbbreviatingWithTildeInPath] retain];
-
-	[defaults setObject:path_to_main_dic forKey:MainDictPathKey];
-
-	SKKServer::sharedServer().getBaseDic().changeDictionaryFile([[self getPathToMainDic] cString]);
-    }
-
-    if(![[[subdic_path stringValue] stringByAbbreviatingWithTildeInPath] isEqualToString:path_to_sub_dic]) {
-	// ƒTƒuŽ«‘‚̏ꏊ‚ª•Ï‚í‚Á‚½
-	[path_to_sub_dic release];
-	path_to_sub_dic = [[[subdic_path stringValue] stringByAbbreviatingWithTildeInPath] retain];
-
-	[defaults setObject:path_to_sub_dic forKey:SubDictPathKey];
-
-	SKKServer::sharedServer().getSubDic().changeDictionaryFile([[self getPathToSubDic] cString]);
-    }
-
-    // ‚±‚Æ‚¦‚莫‘‚ðƒŠƒ[ƒh‚·‚é
-    std::vector<CppCFString> vec;
-    for(unsigned i = 0 ; i < [[self path] count] ; ++ i) {
-	vec.push_back((CFStringRef)[[self path] objectAtIndex:i]);
-    }
-    SKKServer::sharedServer().getKotoeriDic().changeDictionaryFile(vec);
+    // Ž«‘ƒT[ƒo[‚ðÄ‰Šú‰»‚·‚é
+    SKKServer::sharedServer().reload();
 
     Skkserv& skkserv = Skkserv::sharedServer();
     skkserv.setLocalOnly([skkserv_local_only state] == YES ? true : false);
@@ -382,81 +325,6 @@
     return TRUE;
 }
 
-- (IBAction)selectMainDic:(id)sender {
-    // empty
-}
-
-- (IBAction)selectSubDic:(id)sender {
-    // empty
-}
-
-// ‚±‚Æ‚¦‚莫‘
-
-- (IBAction)addKotoeriDic:(id)sender {
-    NSOpenPanel *op = [NSOpenPanel openPanel];
-
-    [op beginSheetForDirectory:NSHomeDirectory()
-                                file:nil
-                                types:nil
-                                modalForWindow:[self window]
-                                modalDelegate:self
-                                didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
-                                contextInfo:NULL];
-
-    [kotoeriDicTable reloadData];
-}
-
-- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void  *)contextInfo {
-    if(returnCode == NSOKButton) {
-        if([dicPath containsObject:[sheet filename]] == YES) {
-            NSBeep();
-            return;
-        }
-
-        if(SKKServer::sharedServer().getKotoeriDic().checkDictionary((CFStringRef)[sheet filename]) == false) {
-            NSBeep();
-            return;
-        }
-
-        [dicPath addObject:[sheet filename]];
-        [self controlSetting];
-        [kotoeriDicTable reloadData];
-    }
-}
-
-- (IBAction)removeKotoeriDic:(id)sender {
-    int selected = [kotoeriDicTable selectedRow];
-    if(selected == -1) {
-	return;
-    }
-    
-    [dicPath removeObjectAtIndex:selected];
-    [self controlSetting];
-    [kotoeriDicTable reloadData];
-}
-
-- (void)controlSetting {
-    [addKotoeriBtn setEnabled:( [dicPath count] == 10 ) ? NO : YES ];
-    [removeKotoeriBtn setEnabled:( [dicPath count] == 0 ) ? NO : YES ];
-}
-
-- (int)numberOfRowsInTableView:(NSTableView *)aTableView {
-    return [dicPath count];
-}
-
-- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex {
-    // Second column
-    if([[aTableColumn identifier] isEqualToString:@"name"])
-        return [dicPath objectAtIndex:rowIndex];
-
-    // Not reach this statement
-    return nil;
-}
-
-- (NSArray *)path {
-    return dicPath;
-}
-
 // skkserv
 - (BOOL)isSkkservEnabled {
     return [skkserv_enabled state];
Index: AquaSKK/SKKServer.cpp
diff -u AquaSKK/SKKServer.cpp:1.4.2.1 AquaSKK/SKKServer.cpp:1.4.2.2
--- AquaSKK/SKKServer.cpp:1.4.2.1	Mon Jan  9 11:11:05 2006
+++ AquaSKK/SKKServer.cpp	Wed Feb 15 00:12:44 2006
@@ -1,5 +1,5 @@
 /*
-  $Id: SKKServer.cpp,v 1.4.2.1 2006/01/09 02:11:05 t-suwa Exp $
+  $Id: SKKServer.cpp,v 1.4.2.2 2006/02/14 15:12:44 t-suwa Exp $
 
   MacOS X implementation of the SKK input method.
 
@@ -21,17 +21,15 @@
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-#include <Carbon/Carbon.h>
 #include <iostream>
-#include <string>
-#include <vector>
-#include <map>
+#include <sstream>
 #include "CppCFString.h"
 #include "OkuriganaEntry.h"
 #include "Dictionary.h"
-#include "DMDictionary.h"
 #include "SKKDictionary.h"
+#include "DMDictionary.h"
 #include "SKKServer.h"
+#include "SkkConfig.h"
 
 #if 0
 #	define D_PRINTF printf
@@ -39,69 +37,160 @@
 #	define D_PRINTF if(0)printf
 #endif
 
+// ’萔‚È‚Ç
+const char* SKK_USER_DICT_PATH = "/Library/AquaSKK/skk-user-dic";
+
+// ƒ†[ƒeƒBƒŠƒeƒB
 static void removeRedundantItems(std::vector<CppCFString>& candidates);
 
-static SKKServer* _shared_instance = NULL;
+// Null Ž«‘
+class NullDictionary: public Dictionary {
+public:
+    NullDictionary(const std::string& location) {
+	// empty
+    }
+    virtual ~NullDictionary() {
+	// empty
+    }
+    virtual int countOkuriAri() {
+	return 0;
+    }
+    virtual int countOkuriNasi() {
+	return 0;
+    }
+    virtual std::vector<OkuriganaEntry> findOkuriAri(const CppCFString& query) {
+	return std::vector<OkuriganaEntry>();
+    }
+    virtual std::vector<CppCFString> findOkuriNasi(const CppCFString& query) {
+	return std::vector<CppCFString>();
+    }
+};
+
+// ƒtƒ@ƒNƒgƒŠƒƒ\ƒbƒh
+Dictionary* SKKServer::createDictionary(const DictionaryPref& pref) const {
+    switch(pref.type) {
+    case SKKDictionaryType:
+	return new SKKDictionary(pref.location);
+	break;
+    case SKKAutoUpdateDictionaryType:
+	return new NullDictionary(pref.location);
+	break;
+    case KotoeriDictionaryType:
+	return new KotoeriDictionary(pref.location);
+	break;
+    case ProxyDictionaryType:
+	return new NullDictionary(pref.location);
+	break;
+    case GroupingDictionaryType:
+	return new NullDictionary(pref.location);
+	break;
+    default:
+	std::cerr << "SKKServer::createDictionary(): unknown type[" << pref.type << "]" << std::endl;
+	break;
+    }
 
-SKKServer& SKKServer::sharedServer() {
-    return *_shared_instance;
+    return new NullDictionary(pref.location);
+}
+
+// map ƒL[¶¬
+std::string SKKServer::generateID(const DictionaryPref& pref) const {
+    std::stringstream id;
+
+    // Ž«‘‚Ì ID ‚𐶐¬‚·‚é
+    id << pref.type << ":" << pref.location;
+
+    return id.str();
+}
+
+void SKKServer::load() {
+    CFArrayRef arrayRef = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("DictionaryInfo"),
+								kCFPreferencesCurrentApplication);
+    if(arrayRef == NULL) {
+	return;
+    }
+
+    // ŒÃ‚¢î•ñ‚ðƒNƒŠƒA‚·‚é
+    prefs_.clear();
+
+    // ŒÂlŽ«‘‚ðæ“ª‚É“ü‚ê‚é
+    DictionaryPref entry;
+    entry.active = true;
+    entry.type = SKKDictionaryType;
+    entry.location = SkkConfig::home() + SKK_USER_DICT_PATH;
+    prefs_.push_back(entry);
+    if(dicts_.find(generateID(entry)) == dicts_.end()) {
+	dicts_[generateID(entry)] = userdict_;
+    }
+
+    // —LŒø‚ÈŽ«‘‚ð‘S‚㍁[ƒh‚·‚é
+    for(CFIndex index = 0; index < CFArrayGetCount(arrayRef); ++ index) {
+	CFDictionaryRef dictRef = (CFDictionaryRef)CFRetain(CFArrayGetValueAtIndex(arrayRef, index));
+
+	// DictionaryPref ‚ðì‚é
+	entry.active = ((CFBooleanRef)CFDictionaryGetValue(dictRef, CFSTR("active")) == kCFBooleanTrue);
+	CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(dictRef, CFSTR("type")), kCFNumberIntType, &entry.type);
+	CFStringRef str = (CFStringRef)CFDictionaryGetValue(dictRef, CFSTR("location"));
+	if(str) {
+	    char buf[2048];
+	    CFStringGetCString(str, buf, sizeof(buf), kCFStringEncodingEUC_JP);
+	    entry.location = buf;
+	} else {
+	    entry.location = "";
+	}
+
+	// ì¬Ï‚Ý‚ÌŽ«‘‚ª‚ ‚ê‚΁AŽæ“¾‚µ‚Ä‚¨‚­
+	DictionaryIterator iter = dicts_.find(generateID(entry));
+
+	// —LŒø‚©H
+	if(entry.active) {
+	    prefs_.push_back(entry);
+
+	    // Œ©‚‚©‚ç‚È‚¯‚ê‚΁A’ljÁ‚µ‚Ä‚¨‚­
+	    if(iter == dicts_.end()) {
+		dicts_[generateID(entry)] = createDictionary(entry);
+	    }
+	} else {
+	    // ì¬Ï‚Ý‚Å–³Œø‚É‚³‚ꂽŽ«‘‚͏Á‚·
+	    if(iter != dicts_.end()) {
+		delete iter->second;
+		dicts_.erase(generateID(entry));
+	    }
+	}
+	CFRelease(dictRef);
+    }
+    CFRelease(arrayRef);
 }
 
-SKKServer&
-SKKServer::sharedServer(const std::string& base_dic_file,
-			const std::string& sub_dic_file,
-			const std::string& user_dic_file,
-			const std::vector<CppCFString>& kotoeri_dic_file) {
-    if(_shared_instance == NULL) {
-	_shared_instance = new SKKServer(base_dic_file, sub_dic_file,
-					 user_dic_file, kotoeri_dic_file);
-    }
-
-    return *_shared_instance;
-}
-
-SKKServer::SKKServer(const std::string& base_dic_file,
-		     const std::string& sub_dic_file,
-		     const std::string& user_dic_file,
-		     const std::vector<CppCFString>& kotoeri_dic_file) {
-    base_dic = new SKKDictionary(base_dic_file);
-    sub_dic = new SKKDictionary(sub_dic_file);
-    user_dic = new SKKUserDictionary(user_dic_file);
-    kotoeri_dic = new DMDictionary(kotoeri_dic_file);
-
-    all_dics.push_back(user_dic);
-    all_dics.push_back(sub_dic);
-    all_dics.push_back(base_dic);
-    all_dics.push_back(kotoeri_dic);
+SKKServer::SKKServer() {
+    userdict_ = new SKKUserDictionary(SkkConfig::home() + SKK_USER_DICT_PATH);
+    load();
 }
 
 SKKServer::~SKKServer() {
     terminate();
 }
 
+SKKServer& SKKServer::sharedServer() {
+    static SKKServer obj;
+    return obj;
+}
+
+void SKKServer::reload() {
+    // Ž«‘‚ðƒ[ƒh‚µ’¼‚·
+    load();
+}
+
 void SKKServer::terminate() {
     struct local {
-	static void DeleteDictionary(Dictionary* ptr) {
-	    delete ptr;
-	    ptr = NULL;
+	static void DeleteDictionary(std::pair<std::string, Dictionary*> entry) {
+	    delete entry.second;
+	    entry.second = NULL;
 	}
     };
 
     // ‘S‚Ä‚ÌŽ«‘‚ðíœ‚·‚é
-    std::for_each(all_dics.begin(), all_dics.end(), local::DeleteDictionary);
-    all_dics.clear();
-}
-
-SKKDictionary& SKKServer::getBaseDic() {
-    return *dynamic_cast<SKKDictionary*>(base_dic);
-}
-
-SKKDictionary& SKKServer::getSubDic() {
-    return *dynamic_cast<SKKDictionary*>(sub_dic);
-}
-
-DMDictionary& SKKServer::getKotoeriDic() {
-    return *dynamic_cast<DMDictionary*>(kotoeri_dic);
+    std::for_each(dicts_.begin(), dicts_.end(), local::DeleteDictionary);
+    dicts_.clear();
 }
 
 CppCFString SKKServer::skkserv_style_search(const CppCFString& query) {
@@ -113,34 +202,33 @@
     }
 
     // ‘—‚è˜ï–¼‚Í—L‚é‚©H
-    if(query[0] > 0xff &&
-       query[query.length()-1] >= 'a' && query[query.length()-1] <= 'z') {
+    if(query[0] > 0xff && query[query.length() - 1] >= 'a' && query[query.length() - 1] <= 'z') {
 	// OkuriganaEntry.kana => OkuriganaEntry
 	std::map<CppCFString, OkuriganaEntry> cands;
-	for(std::vector<Dictionary*>::const_iterator dic = all_dics.begin();
-	    dic != all_dics.end(); ++ dic) {
+	for(DictionaryPrefIterator iter = prefs_.begin(); iter != prefs_.end(); ++ iter) {
+	    // ƒOƒ‹[ƒvŽ«‘‚̏ꍇAŠù‚ÉŒó•â‚ªŒ©‚‚©‚Á‚Ä‚¢‚ê‚ÎŒŸõ‚ð‚â‚ß‚é
+	    if(iter->type == GroupingDictionaryType && !cands.empty()) {
+		break;
+	    }
 
-	    std::vector<OkuriganaEntry> vec_okuri = (*dic)->findOkuriAri(query);
-	    if(vec_okuri.empty()) {
+	    Dictionary* dict = dicts_[generateID(*iter)];
+	    std::vector<OkuriganaEntry> okuriEntries = dict->findOkuriAri(query);
+	    if(okuriEntries.empty()) {
 		continue;
 	    }
 
-	    for(std::vector<OkuriganaEntry>::iterator e = vec_okuri.begin();
-		 e != vec_okuri.end(); ++ e) {
+	    for(std::vector<OkuriganaEntry>::iterator e = okuriEntries.begin(); e != okuriEntries.end(); ++ e) {
 		OkuriganaEntry& entry = cands[e->getKana()];
 		entry.setKana(e->getKana());
-		entry.getCandidates().insert(
-		    entry.getCandidates().begin(),
-		    e->getCandidates().begin(),
-		    e->getCandidates().end());
+		entry.getCandidates().insert(entry.getCandidates().begin(),
+					     e->getCandidates().begin(), e->getCandidates().end());
 	    }
 	}
 
 	// ‘S‚ẴGƒ“ƒgƒŠ‚ɂ‚¢‚āAd•¡‚µ‚Ä‚î‚é‚à‚Ì‚ðíœ‚µ‚È‚ª‚çAƒŠƒv
 	// ƒ‰ƒC‚ð‘g—§‚Ä‚éB
 	CppCFString reply;
-	for(std::map<CppCFString, OkuriganaEntry>::iterator e = cands.begin();
-	    e != cands.end(); ++ e) {
+	for(std::map<CppCFString, OkuriganaEntry>::iterator e = cands.begin(); e != cands.end(); ++ e) {
 	    OkuriganaEntry& entry = e->second;
 	    entry.removeRedundantItems();
 	    if(entry.isWild()) {
@@ -158,14 +246,16 @@
 	// ‘—‚è˜ï–¼‚ª–³‚¢B
 	std::vector<CppCFString> cands;
 
-	for(std::vector<Dictionary*>::const_iterator ite = all_dics.begin();
-	    ite != all_dics.end(); ++ ite) {
+	for(DictionaryPrefIterator iter = prefs_.begin(); iter != prefs_.end(); ++ iter) {
+	    // ƒOƒ‹[ƒvŽ«‘‚̏ꍇAŠù‚ÉŒó•â‚ªŒ©‚‚©‚Á‚Ä‚¢‚ê‚ÎŒŸõ‚ð‚â‚ß‚é
+	    if(iter->type == GroupingDictionaryType && !cands.empty()) {
+		break;
+	    }
 
-	    std::vector<CppCFString> cand_for_one = (*ite)->findOkuriNasi(query);
-	    if(cand_for_one.size() > 0) {
-		cands.insert(cands.end(),
-			     cand_for_one.begin(),
-			     cand_for_one.end());
+	    Dictionary* dict = dicts_[generateID(*iter)];
+	    std::vector<CppCFString> result = dict->findOkuriNasi(query);
+	    if(!result.empty()) {
+		cands.insert(cands.end(), result.begin(), result.end());
 	    }
 	}
 
@@ -195,36 +285,33 @@
 	
 	std::vector<CppCFString> cand_strictly_matched;
 	std::vector<CppCFString> cand_unstrictly_matched;
-	for(std::vector<Dictionary*>::const_iterator dic = all_dics.begin();
-	    dic != all_dics.end(); ++ dic) {
-	    std::vector<OkuriganaEntry> vec_okuri = (*dic)->findOkuriAri(root);
-	    if(vec_okuri.empty()) continue;
-
-	    for(std::vector<OkuriganaEntry>::const_iterator
-		    okuri_entry = vec_okuri.begin();
-		okuri_entry != vec_okuri.end(); ++ okuri_entry) {
-		// ‚±‚ÌOkuriganaEntry‚ÌŒ©o‚µ‚Æokuri‚ªˆê’v‚µ‚Ä‚¢‚½‚ç
-		// cand_strictly_matched‚É“ü‚êAˆê’v‚µ‚Ä‚¢‚È‚¯‚ê‚Î
-		// cand_unstrictly_matched‚É“ü‚ê‚éB
-		if(okuri_entry->getKana() == okuri) {
-		    cand_strictly_matched.insert(
-			cand_strictly_matched.end(),
-			okuri_entry->getCandidates().begin(),
-			okuri_entry->getCandidates().end());
+
+	for(DictionaryPrefIterator iter = prefs_.begin(); iter != prefs_.end(); ++ iter) {
+	    // ƒOƒ‹[ƒvŽ«‘‚̏ꍇAŠù‚ÉŒó•â‚ªŒ©‚‚©‚Á‚Ä‚¢‚ê‚ÎŒŸõ‚ð‚â‚ß‚é
+	    if(iter->type == GroupingDictionaryType &&
+	       (!cand_strictly_matched.empty() || !cand_unstrictly_matched.empty())) {
+		break;
+	    }
+
+	    Dictionary* dict = dicts_[generateID(*iter)];
+	    std::vector<OkuriganaEntry> okuriEntries = dict->findOkuriAri(root);
+	    if(okuriEntries.empty()) {
+		continue;
+	    }
+
+	    for(std::vector<OkuriganaEntry>::iterator e = okuriEntries.begin(); e != okuriEntries.end(); ++ e) {
+		if(e->getKana() == okuri) {
+		    cand_strictly_matched.insert(cand_strictly_matched.end(),
+						 e->getCandidates().begin(), e->getCandidates().end());
 		} else {
-		    cand_unstrictly_matched.insert(
-			cand_unstrictly_matched.end(),
-			okuri_entry->getCandidates().begin(),
-			okuri_entry->getCandidates().end());
+		    cand_unstrictly_matched.insert(cand_unstrictly_matched.end(),
+						   e->getCandidates().begin(), e->getCandidates().end());
 		}
 	    }
 	}
 
 	std::vector<CppCFString> candidates = cand_strictly_matched;
-	candidates.insert(
-	    candidates.end(),
-	    cand_unstrictly_matched.begin(),
-	    cand_unstrictly_matched.end());
+	candidates.insert(candidates.end(), cand_unstrictly_matched.begin(), cand_unstrictly_matched.end());
 
 	// candidates‚̏d•¡‚ðƒ`ƒFƒbƒNBd•¡‚µ‚Ä‚¢‚½‚çŒã‚É‚ ‚é‚à‚Ì‚ðíœB
 	removeRedundantItems(candidates);
@@ -232,8 +319,7 @@
 	// ‚±‚ÌŽž“_‚Åcandidates‚É“ü‚Á‚Ä‚¢‚é‚Ì‚ÍŠ¿Žš‚Ì•”•ª‚¾‚¯‚Ȃ̂ŁA
 	// ‘S‚Ä‚Ì—v‘f‚É‘—‚艼–¼‚ð•t‚¯‚éB“¯Žž‚ɃXƒy[ƒX‚ð[20]‚É•ÏŠ·B
 	// ’Žß‚ª•t‚¢‚Ä‚¢‚ê‚΁Aíœ‚·‚éB(Žb’è)
-	for(std::vector<CppCFString>::iterator ite = candidates.begin();
-	    ite != candidates.end(); ++ ite) {
+	for(std::vector<CppCFString>::iterator ite = candidates.begin(); ite != candidates.end(); ++ ite) {
 	    const int semicolon_pos = ite->indexOf(';');
 	    if(semicolon_pos != -1) {
 		ite->erase(semicolon_pos, ite->length());
@@ -245,12 +331,20 @@
 	return join(' ', candidates);
     } else {
 	std::vector<CppCFString> candidates;
-	for(std::vector<Dictionary*>::const_iterator ite = all_dics.begin();
-	    ite != all_dics.end(); ++ ite) {
-	    std::vector<CppCFString> cand_for_one = (*ite)->findOkuriNasi(query_str);
-	    if(cand_for_one.size() > 0)
-		candidates.insert(candidates.end(),
-				  cand_for_one.begin(), cand_for_one.end());
+
+	for(DictionaryPrefIterator iter = prefs_.begin(); iter != prefs_.end(); ++ iter) {
+	    // ƒOƒ‹[ƒvŽ«‘‚̏ꍇAŠù‚ÉŒó•â‚ªŒ©‚‚©‚Á‚Ä‚¢‚ê‚ÎŒŸõ‚ð‚â‚ß‚é
+	    if(iter->type == GroupingDictionaryType && !candidates.empty()) {
+		break;
+	    }
+
+	    Dictionary* dict = dicts_[generateID(*iter)];
+	    std::vector<CppCFString> result = dict->findOkuriNasi(query_str);
+	    if(result.empty()) {
+		continue;
+	    }
+
+	    candidates.insert(candidates.end(), result.begin(), result.end());
 	}
 
 	// candidates‚̏d•¡‚ðƒ`ƒFƒbƒNBd•¡‚µ‚Ä‚¢‚½‚çŒã‚É‚ ‚é‚à‚Ì‚ðíœB
@@ -258,8 +352,7 @@
 
 	// candidates‚Ì‘S‚Ă̍€–ڂ̃Xƒy[ƒX‚ð[20]‚É•ÏŠ·B
 	// ’Žß‚ª•t‚¢‚Ä‚¢‚ê‚΁Aíœ‚·‚éB(Žb’è)
-	for(std::vector<CppCFString>::iterator ite = candidates.begin();
-	    ite != candidates.end(); ++ ite) {
+	for(std::vector<CppCFString>::iterator ite = candidates.begin(); ite != candidates.end(); ++ ite) {
 	    const int semicolon_pos = ite->indexOf(';');
 	    if(semicolon_pos != -1) {
 		ite->erase(semicolon_pos, ite->length());
@@ -295,7 +388,7 @@
 		      << index.length() << " okuri:" << okuri.length()
 		      << " kanji:" << kanji.length() << " (len)" << std::endl;
 	} else {
-	    user_dic->registerOkuriAri(index, okuri, kanji);
+	    userdict_->registerOkuriAri(index, okuri, kanji);
 	}
     } else {
 	// ‘—‚艼–¼–³‚µBu-‚©‚È ‰¼–¼v
@@ -310,7 +403,7 @@
 		      << index.length() << " kanji:" << kanji.length()
 		      << " (len)" << std::endl;
 	} else {
-	    user_dic->registerOkuriNasi(index, kanji);
+	    userdict_->registerOkuriNasi(index, kanji);
 	}
     }
 }
@@ -338,7 +431,7 @@
 		      << index.length() << " okuri:" << okuri.length()
 		      << " kanji:" << kanji.length() << " (len)" << std::endl;
 	} else {
-	    user_dic->removeOkuriAri(index, kanji);
+	    userdict_->removeOkuriAri(index, kanji);
 	}
     } else {
 	// ‘—‚艼–¼–³‚µBu-‚©‚È ‰¼–¼v
@@ -353,7 +446,7 @@
 		      << index.length() << " kanji:" << kanji.length()
 		      << " (len)" << std::endl;
 	} else {
-	    user_dic->removeOkuriNasi(index, kanji);
+	    userdict_->removeOkuriNasi(index, kanji);
 	}
     }
 }
@@ -365,7 +458,7 @@
     D_PRINTF("COMPLETE: %s\n", query.toCString(kCFStringEncodingEUC_JP));
 
     CppCFString head = query.replaceClone(nbsp, space);
-    std::vector<CppCFString> result = user_dic->findCompletions(head);
+    std::vector<CppCFString> result = userdict_->findCompletions(head);
 
     D_PRINTF("REPLY: %s\n",
 	     join(' ',result).toCString(kCFStringEncodingEUC_JP));
Index: AquaSKK/SKKServer.h
diff -u AquaSKK/SKKServer.h:1.3 AquaSKK/SKKServer.h:1.3.2.1
--- AquaSKK/SKKServer.h:1.3	Wed Nov  9 00:02:24 2005
+++ AquaSKK/SKKServer.h	Wed Feb 15 00:12:44 2006
@@ -1,11 +1,10 @@
 /* -*- c++ -*-
-  $Id: SKKServer.h,v 1.3 2005/11/08 15:02:24 t-suwa Exp $
-  ---------
-	
+  $Id: SKKServer.h,v 1.3.2.1 2006/02/14 15:12:44 t-suwa Exp $
+
   MacOS X implementation of the SKK input method.
 
   Copyright (C) 2002 phonohawk
-  Copyright (C) 2005 Tomotaka SUWA <t.suw****@mac*****>
+  Copyright (C) 2005-2006 Tomotaka SUWA <t.suw****@mac*****>
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -26,44 +25,51 @@
 
 #include <string>
 #include <vector>
+#include <map>
 
 class CppCFString;
 class Dictionary;
 class UserDictionary;
-class SKKDictionary;
-class DMDictionary;
-
-/*
-	‰Šú‰»‚ð•K—v‚Æ‚·‚éSingleton‚Å‚ ‚éB
-	Žg—p‚·‚é‘O‚ÉsharedServer(string,string,string)‚ðŒÄ‚΂Ȃ­‚Ä‚Í‚È‚ç‚È‚¢B
-	
-	c‚»‚Ì‚¤‚¿C³‚µ‚Ü‚·BŽ©—Í‚ÅŽ«‘‚̏ꏊ‚ðŽæ“¾‚·‚é‚Ì‚ª³‚µ‚¢‚ÆŽv‚¤c
-*/
 
 class SKKServer {
-    Dictionary* base_dic;
-    Dictionary* sub_dic;
-    UserDictionary* user_dic;
-    Dictionary* kotoeri_dic;
-    std::vector<Dictionary*> all_dics;
-
-    SKKServer(const std::string& base_dic_file,
-	      const std::string& sub_dic_file,
-	      const std::string& user_dic_file,
-	      const std::vector<CppCFString>& kotoeri_dic_file);
-    virtual ~SKKServer();
+    // Ž«‘‚ÌŽí—Þ
+    enum DictionaryTypes {
+	SKKDictionaryType = 10,
+	SKKAutoUpdateDictionaryType = 11,
+	KotoeriDictionaryType = 20,
+	ProxyDictionaryType = 30,
+	GroupingDictionaryType = 90,
+    };
+
+    // Ž«‘‚̐ݒè
+    struct DictionaryPref {
+	bool active;
+	int type;
+	std::string location;
+    };
+    typedef std::vector<DictionaryPref> DictionaryPrefContainer;
+    typedef DictionaryPrefContainer::iterator DictionaryPrefIterator;
+    typedef std::map<std::string, Dictionary*> DictionaryContainer;
+    typedef DictionaryContainer::iterator DictionaryIterator;
+
+    // ƒ†[ƒU[Ž«‘
+    UserDictionary* userdict_;
+
+    DictionaryPrefContainer prefs_;
+    DictionaryContainer dicts_;
+
+    Dictionary* createDictionary(const DictionaryPref& pref) const;
+    std::string generateID(const DictionaryPref& pref) const;
+    void load();
+
+    SKKServer();
+    ~SKKServer();
 
 public:
-    static SKKServer& sharedServer(const std::string& base_dic_file,
-				   const std::string& sub_dic_file,
-				   const std::string& user_dic_file,
-				   const std::vector<CppCFString>& kotoeri_dic_file);
     static SKKServer& sharedServer();
-    void terminate();
 
-    SKKDictionary& getBaseDic();
-    SKKDictionary& getSubDic();
-    DMDictionary& getKotoeriDic();
+    void reload();
+    void terminate();
 
     CppCFString skkserv_style_search(const CppCFString& query); // NOT FOUND‚È‚ç‹ó‚Ì•¶Žš—ñ‚ð•Ô‚·B
     CppCFString search(const CppCFString& query); // NOT FOUND‚È‚ç‹ó‚Ì•¶Žš—ñ‚ð•Ô‚·B


aquaskk-changes メーリングリストの案内