最小限データーベースその3

コピペとDrag&Dropのデータタイプを増やす。

今までは、自分自身が作成した、データタイプ “com.mindto01s.M3XNote” しかコピペもDrag&Dropも出来なかった。

そのため、newコマンドで項目ノートを作成してから、TextViewへデータをペーストしていた。

これを、Pasteboard に、以下のデータタイプがある場合は、ペーストコマンドで自動で項目ノートの作成とそのノートへのペーストを一手間でできるようにした。

Dropの受け入れ

[M3XViewController viewDidLoad] で [M3XNote pasteBoardRowsType]を[M3XNote pasteBoardRowsTypes]とするだけ。

[self.browserView registerForDraggedTypes:[M3XNote pasteBoardRowsTypes]];

[M3XNote pasteBoardRowsTypes]の方では、以下のように受け入れ可能なUTIを列挙している。

+ (NSArray<NSString*>*) pasteBoardRowsTypes
{
    return @[
             [self pasteBoardRowsType],
             NSPasteboardTypeRTFD,
             NSPasteboardTypeRTF,
             NSPasteboardTypeString,
             NSPasteboardTypePNG, // <-- 入力のみ
             NSPasteboardTypeTIFF,  // <-- 入力のみ
             ];
}

この変更だけで、Dropはは可能になる。もちろんDropした後のコードは何も書いていないので、Dropした瞬間に落ちるはず。

ペーストボードへの書き込み

この変更は、[M3XNote wreiteToPasteboard:]の中だけ。

ペーストボードには複数のデータタイプを入れられるので、今までのコードの末尾に、書き出したいデータのコードを書き足すだけ。

- (void) wreiteToPasteboard:(NSPasteboard*)pasteboard
{
    .
    .
    .

    // 以下から書き足したコード
    NSAttributedString* theAttributedString = [[NSAttributedString alloc] initWithRTFD:self.memo documentAttributes:nil];

    [pasteboard setData:[theAttributedString RTFDFromRange:NSMakeRange(0, theAttributedString.length)
                                        documentAttributes:@{}]
                forType:NSPasteboardTypeRTFD];

    [pasteboard setData:[theAttributedString RTFFromRange:NSMakeRange(0, theAttributedString.length)
                                       documentAttributes:@{}]
                forType:NSPasteboardTypeRTF];

    [pasteboard setString:theAttributedString.string
                  forType:NSPasteboardTypeString];
}

ペーストボードに対してsetData:forTypeなどで書き出している。

ここまでのコードを書くと、このアプリの項目ノートを他のテキストエディターなどペースト出来るようになる。

ペーストボードからの読み出し

読み出しのコードはかなり汚い。

上から順番に、欲しいデータが存在したら処理をしている。独自データが最優先で、次にRTFDなどの文字列系が続き、最後は画像データの順番になっている。

RTFDなどの文字列系は以下のように単純に、NSData型に変換してCoreDataに入れているだけ。

+ (instancetype) readFromPasteboard:(NSPasteboard*)pasteboard
             inManagedObjectContext:(NSManagedObjectContext *)context
{
    M3XNote* theResult = nil;

    .
    .
    .
    // RTFD
    NSData* theRTFD = [pasteboard dataForType:NSPasteboardTypeRTFD];

    if( theRTFD != nil )
    {
        theResult = [NSEntityDescription insertNewObjectForEntityForName:@"M3XNote"
                                                  inManagedObjectContext:context];

        theResult.memo = theRTFD;
        theResult.isHome = NO;

        return theResult;
    }
    .
    .
    .
}

最後の画像系のデータだけ少しだけ複雑なことを行なっている。

NSTextViewはRTFDのデータを表示する機能はあるが、NSImageViewのように直接Imageを設定はできない。 そのため、NSTextAttachmentを使用して、画像を貼り付ける形になる。

+ (instancetype) readFromPasteboard:(NSPasteboard*)pasteboard
             inManagedObjectContext:(NSManagedObjectContext *)context
{
    M3XNote* theResult = nil;

    .
    .
    .
    // PNG or TIFF
    NSData* theImageData;
    theImageData = [pasteboard dataForType:NSPasteboardTypePNG];
    if( theImageData == nil )
    {
        theImageData = [pasteboard dataForType:NSPasteboardTypeTIFF];
    }

    if( theImageData != nil )
    {
        theResult = [NSEntityDescription insertNewObjectForEntityForName:@"M3XNote"
                                                  inManagedObjectContext:context];

        NSDateFormatter* theDateFormatter = [[NSDateFormatter alloc] init];
        [theDateFormatter setDateFormat:@"yy/MM/dd H:mm:ss"];

        NSString* theMemoString = [NSString stringWithFormat:@"画像 : %@\n", [theDateFormatter stringFromDate:[NSDate date]]];

        NSMutableAttributedString* theAttributedString = [[NSMutableAttributedString alloc] initWithString:theMemoString];

        NSTextAttachment* theAttachment = [[NSTextAttachment alloc] init];
        theAttachment.image = [[NSImage alloc] initWithData:theImageData];
        NSAttributedString* theAttatchText = [NSAttributedString attributedStringWithAttachment:theAttachment];

        [theAttributedString appendAttributedString:theAttatchText];

        theResult.memo = [theAttributedString RTFDFromRange:NSMakeRange(0, theAttributedString.length)
                                         documentAttributes:@{}];
        theResult.isHome = NO;

        return theResult;
    }
    .
    .
    .
}

ここまで出来れば、他のアプリからこのアプリへコピー&ペーストが出来るようになる。

今後の課題

実装していないものとして、URLとhtmlのデータタイプがある。これがないために、SafariからURLのDrag&Dropで項目ノートを作成することは出来ない。

これは、現在のアプリのデータ構造の持ち方では、サーバーからデータを取得する時に、メインスレッドをブロックする必要がありそうなので、実装しなかった。

同じく、ファイルDropも実装しなかった。画像ファイルやRTFDファイルをDrop可能にしようかとも考えたが、サイズの大きいデータを考慮していない設計なのでこれも実装しなかった。

今回はここまで。多分続きはなし。( microMemex3.zip )

なんか、code-blockが上手く働いてくれないなぁ。でも、眠いから寝る。