of "bemail". * Automatic whitespace cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33554 a95241bf-73f2-0310-859d-f6bbb57e9c96
613 lines
15 KiB
C++
613 lines
15 KiB
C++
/*
|
|
Open Tracker License
|
|
|
|
Terms and Conditions
|
|
|
|
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
this software and associated documentation files (the "Software"), to deal in
|
|
the Software without restriction, including without limitation the rights to
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
of the Software, and to permit persons to whom the Software is furnished to do
|
|
so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice applies to all licensees
|
|
and shall be included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of Be Incorporated shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings in
|
|
this Software without prior written authorization from Be Incorporated.
|
|
|
|
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
|
of Be Incorporated in the United States and other countries. Other brand product
|
|
names are registered trademarks or trademarks of their respective holders.
|
|
All rights reserved.
|
|
*/
|
|
|
|
#include "Signature.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <Clipboard.h>
|
|
#include <InterfaceKit.h>
|
|
#include <StorageKit.h>
|
|
|
|
#include "MailApp.h"
|
|
#include "MailPopUpMenu.h"
|
|
#include "MailSupport.h"
|
|
#include "MailWindow.h"
|
|
#include "Messages.h"
|
|
|
|
#include <MDRLanguage.h>
|
|
|
|
|
|
extern BRect signature_window;
|
|
extern const char *kUndoStrings[];
|
|
extern const char *kRedoStrings[];
|
|
|
|
const char kNameText[] = MDR_DIALECT_CHOICE ("Title:", "署名の名称:");
|
|
const char kSigText[] = MDR_DIALECT_CHOICE ("Signature:", "署名:");
|
|
|
|
|
|
//====================================================================
|
|
|
|
TSignatureWindow::TSignatureWindow(BRect rect)
|
|
: BWindow (rect, MDR_DIALECT_CHOICE ("Signatures","署名の編集"), B_TITLED_WINDOW, 0),
|
|
fFile(NULL)
|
|
{
|
|
BMenu *menu;
|
|
BMenuBar *menu_bar;
|
|
BMenuItem *item;
|
|
|
|
BRect r = Bounds();
|
|
/*** Set up the menus ****/
|
|
menu_bar = new BMenuBar(r, "MenuBar");
|
|
menu = new BMenu(MDR_DIALECT_CHOICE ("Signature","S) 署名"));
|
|
menu->AddItem(fNew = new BMenuItem(MDR_DIALECT_CHOICE ("New","N) 新規"), new BMessage(M_NEW), 'N'));
|
|
fSignature = new TMenu(MDR_DIALECT_CHOICE ("Open","O) 開く"), INDEX_SIGNATURE, M_SIGNATURE);
|
|
menu->AddItem(new BMenuItem(fSignature));
|
|
menu->AddSeparatorItem();
|
|
menu->AddItem(fSave = new BMenuItem(MDR_DIALECT_CHOICE ("Save","S) 保存"), new BMessage(M_SAVE), 'S'));
|
|
menu->AddItem(fDelete = new BMenuItem(MDR_DIALECT_CHOICE ("Delete","T) 削除"), new BMessage(M_DELETE), 'T'));
|
|
menu_bar->AddItem(menu);
|
|
|
|
menu = new BMenu(MDR_DIALECT_CHOICE ("Edit","E) 編集"));
|
|
menu->AddItem(fUndo = new BMenuItem(MDR_DIALECT_CHOICE ("Undo","Z) やり直し"), new BMessage(B_UNDO), 'Z'));
|
|
fUndo->SetTarget(NULL, this);
|
|
menu->AddSeparatorItem();
|
|
menu->AddItem(fCut = new BMenuItem(MDR_DIALECT_CHOICE ("Cut","X) 切り取り"), new BMessage(B_CUT), 'X'));
|
|
fCut->SetTarget(NULL, this);
|
|
menu->AddItem(fCopy = new BMenuItem(MDR_DIALECT_CHOICE ("Copy","C) コピー"), new BMessage(B_COPY), 'C'));
|
|
fCopy->SetTarget(NULL, this);
|
|
menu->AddItem(fPaste = new BMenuItem(MDR_DIALECT_CHOICE ("Paste","V) 貼り付け"), new BMessage(B_PASTE), 'V'));
|
|
fPaste->SetTarget(NULL, this);
|
|
menu->AddSeparatorItem();
|
|
menu->AddItem(item = new BMenuItem(MDR_DIALECT_CHOICE ("Select All","A) 全文選択"), new BMessage(M_SELECT), 'A'));
|
|
item->SetTarget(NULL, this);
|
|
menu_bar->AddItem(menu);
|
|
|
|
AddChild(menu_bar);
|
|
/**** Done with the menu set up *****/
|
|
|
|
/**** Add on the panel, giving it the width and at least one vertical pixel *****/
|
|
fSigView = new TSignatureView(BRect(0, menu_bar->Frame().bottom+1,
|
|
rect.Width(), menu_bar->Frame().bottom+2));
|
|
AddChild(fSigView);
|
|
|
|
/* resize the window to the correct height */
|
|
fSigView->SetResizingMode(B_FOLLOW_NONE);
|
|
ResizeTo(rect.Width()-2, fSigView->Frame().bottom-2);
|
|
fSigView->SetResizingMode(B_FOLLOW_ALL);
|
|
|
|
SetSizeLimits(kSigWidth, RIGHT_BOUNDARY, r.top + 100, RIGHT_BOUNDARY);
|
|
}
|
|
|
|
|
|
TSignatureWindow::~TSignatureWindow()
|
|
{
|
|
}
|
|
|
|
|
|
void
|
|
TSignatureWindow::MenusBeginning()
|
|
{
|
|
int32 finish = 0;
|
|
int32 start = 0;
|
|
BTextView *text_view;
|
|
|
|
fDelete->SetEnabled(fFile);
|
|
fSave->SetEnabled(IsDirty());
|
|
fUndo->SetEnabled(false); // ***TODO***
|
|
|
|
text_view = (BTextView *)fSigView->fName->ChildAt(0);
|
|
if (text_view->IsFocus())
|
|
text_view->GetSelection(&start, &finish);
|
|
else
|
|
fSigView->fTextView->GetSelection(&start, &finish);
|
|
|
|
fCut->SetEnabled(start != finish);
|
|
fCopy->SetEnabled(start != finish);
|
|
|
|
fNew->SetEnabled(text_view->TextLength() | fSigView->fTextView->TextLength());
|
|
be_clipboard->Lock();
|
|
fPaste->SetEnabled(be_clipboard->Data()->HasData("text/plain", B_MIME_TYPE));
|
|
be_clipboard->Unlock();
|
|
|
|
// Undo stuff
|
|
bool isRedo = false;
|
|
undo_state undoState = B_UNDO_UNAVAILABLE;
|
|
|
|
BTextView *focusTextView = dynamic_cast<BTextView *>(CurrentFocus());
|
|
if (focusTextView != NULL)
|
|
undoState = focusTextView->UndoState(&isRedo);
|
|
|
|
fUndo->SetLabel((isRedo) ? kRedoStrings[undoState] : kUndoStrings[undoState]);
|
|
fUndo->SetEnabled(undoState != B_UNDO_UNAVAILABLE);
|
|
}
|
|
|
|
|
|
void
|
|
TSignatureWindow::MessageReceived(BMessage* msg)
|
|
{
|
|
char *sig;
|
|
char name[B_FILE_NAME_LENGTH];
|
|
BFont *font;
|
|
BTextView *text_view;
|
|
entry_ref ref;
|
|
off_t size;
|
|
|
|
switch(msg->what) {
|
|
case CHANGE_FONT:
|
|
msg->FindPointer("font", (void **)&font);
|
|
fSigView->fTextView->SetFontAndColor(font);
|
|
fSigView->fTextView->Invalidate(fSigView->fTextView->Bounds());
|
|
break;
|
|
|
|
case M_NEW:
|
|
if (Clear()) {
|
|
fSigView->fName->SetText("");
|
|
// fSigView->fTextView->SetText(NULL, (int32)0);
|
|
fSigView->fTextView->SetText("");
|
|
fSigView->fName->MakeFocus(true);
|
|
}
|
|
break;
|
|
|
|
case M_SAVE:
|
|
Save();
|
|
break;
|
|
|
|
case M_DELETE:
|
|
if (!(new BAlert("",MDR_DIALECT_CHOICE (
|
|
"Really delete this signature? This cannot be undone.",
|
|
"この署名を削除しますか?"),
|
|
MDR_DIALECT_CHOICE ("Cancel","取消l"),
|
|
MDR_DIALECT_CHOICE ("Delete","削除"), NULL, B_WIDTH_AS_USUAL,
|
|
B_WARNING_ALERT))->Go())
|
|
break;
|
|
|
|
if (fFile) {
|
|
delete fFile;
|
|
fFile = NULL;
|
|
fEntry.Remove();
|
|
fSigView->fName->SetText("");
|
|
fSigView->fTextView->SetText(NULL, (int32)0);
|
|
fSigView->fName->MakeFocus(true);
|
|
}
|
|
break;
|
|
|
|
case M_SIGNATURE:
|
|
if (Clear()) {
|
|
msg->FindRef("ref", &ref);
|
|
fEntry.SetTo(&ref);
|
|
fFile = new BFile(&ref, O_RDWR);
|
|
if (fFile->InitCheck() == B_NO_ERROR) {
|
|
fFile->ReadAttr(INDEX_SIGNATURE, B_STRING_TYPE, 0, name, sizeof(name));
|
|
fSigView->fName->SetText(name);
|
|
fFile->GetSize(&size);
|
|
sig = (char *)malloc(size);
|
|
size = fFile->Read(sig, size);
|
|
fSigView->fTextView->SetText(sig, size);
|
|
fSigView->fName->MakeFocus(true);
|
|
text_view = (BTextView *)fSigView->fName->ChildAt(0);
|
|
text_view->Select(0, text_view->TextLength());
|
|
fSigView->fTextView->fDirty = false;
|
|
}
|
|
else {
|
|
fFile = NULL;
|
|
beep();
|
|
(new BAlert("", MDR_DIALECT_CHOICE (
|
|
"Couldn't open this signature. Sorry.",
|
|
"署名を開く時にエラーが発生しました。"),
|
|
MDR_DIALECT_CHOICE ("OK","了解")))->Go();
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
BWindow::MessageReceived(msg);
|
|
}
|
|
}
|
|
|
|
|
|
bool
|
|
TSignatureWindow::QuitRequested()
|
|
{
|
|
if (Clear()) {
|
|
BMessage msg(WINDOW_CLOSED);
|
|
msg.AddInt32("kind", SIG_WINDOW);
|
|
msg.AddRect("window frame", Frame());
|
|
|
|
be_app->PostMessage(&msg);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
void
|
|
TSignatureWindow::FrameResized(float width, float height)
|
|
{
|
|
fSigView->FrameResized(width, height);
|
|
}
|
|
|
|
|
|
void
|
|
TSignatureWindow::Show()
|
|
{
|
|
BTextView *text_view;
|
|
|
|
Lock();
|
|
text_view = (BTextView *)fSigView->fName->TextView();
|
|
fSigView->fName->MakeFocus(true);
|
|
text_view->Select(0, text_view->TextLength());
|
|
Unlock();
|
|
|
|
BWindow::Show();
|
|
}
|
|
|
|
|
|
bool
|
|
TSignatureWindow::Clear()
|
|
{
|
|
int32 result;
|
|
|
|
if (IsDirty()) {
|
|
beep();
|
|
BAlert *alert = new BAlert("",
|
|
MDR_DIALECT_CHOICE ("Save changes to this signature?","変更した署名を保存しますか?"),
|
|
MDR_DIALECT_CHOICE ("Don't Save","保存しない"),
|
|
MDR_DIALECT_CHOICE ("Cancel","中止"),
|
|
MDR_DIALECT_CHOICE ("Save","保存する"),
|
|
B_WIDTH_AS_USUAL, B_WARNING_ALERT);
|
|
alert->SetShortcut(0,'d');
|
|
alert->SetShortcut(1,B_ESCAPE);
|
|
result = alert->Go();
|
|
if (result == 1)
|
|
return false;
|
|
if (result == 2)
|
|
Save();
|
|
}
|
|
|
|
delete fFile;
|
|
fFile = NULL;
|
|
fSigView->fTextView->fDirty = false;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool
|
|
TSignatureWindow::IsDirty()
|
|
{
|
|
char name[B_FILE_NAME_LENGTH];
|
|
|
|
if (fFile) {
|
|
fFile->ReadAttr(INDEX_SIGNATURE, B_STRING_TYPE, 0, name, sizeof(name));
|
|
if ((strcmp(name, fSigView->fName->Text())) || (fSigView->fTextView->fDirty))
|
|
return true;
|
|
}
|
|
else {
|
|
if ((strlen(fSigView->fName->Text())) ||
|
|
(fSigView->fTextView->TextLength()))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
void
|
|
TSignatureWindow::Save()
|
|
{
|
|
char name[B_FILE_NAME_LENGTH];
|
|
int32 index = 0;
|
|
status_t result;
|
|
BDirectory dir;
|
|
BEntry entry;
|
|
BNodeInfo *node;
|
|
BPath path;
|
|
|
|
if (!fFile) {
|
|
find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
|
|
dir.SetTo(path.Path());
|
|
|
|
if (dir.FindEntry("Mail", &entry) == B_NO_ERROR)
|
|
dir.SetTo(&entry);
|
|
else
|
|
dir.CreateDirectory("Mail", &dir);
|
|
|
|
if (dir.InitCheck() != B_NO_ERROR)
|
|
goto err_exit;
|
|
|
|
if (dir.FindEntry("signatures", &entry) == B_NO_ERROR)
|
|
dir.SetTo(&entry);
|
|
else
|
|
dir.CreateDirectory("signatures", &dir);
|
|
|
|
if (dir.InitCheck() != B_NO_ERROR)
|
|
goto err_exit;
|
|
|
|
fFile = new BFile();
|
|
while(true) {
|
|
sprintf(name, "signature_%ld", index++);
|
|
if ((result = dir.CreateFile(name, fFile, true)) == B_NO_ERROR)
|
|
break;
|
|
if (result != EEXIST)
|
|
goto err_exit;
|
|
}
|
|
dir.FindEntry(name, &fEntry);
|
|
node = new BNodeInfo(fFile);
|
|
node->SetType("text/plain");
|
|
delete node;
|
|
}
|
|
|
|
fSigView->fTextView->fDirty = false;
|
|
fFile->Seek(0, 0);
|
|
fFile->Write(fSigView->fTextView->Text(),
|
|
fSigView->fTextView->TextLength());
|
|
fFile->SetSize(fFile->Position());
|
|
fFile->WriteAttr(INDEX_SIGNATURE, B_STRING_TYPE, 0, fSigView->fName->Text(),
|
|
strlen(fSigView->fName->Text()) + 1);
|
|
return;
|
|
|
|
err_exit:
|
|
beep();
|
|
(new BAlert("", MDR_DIALECT_CHOICE (
|
|
"An error occurred trying to save this signature.",
|
|
"署名を保存しようとした時にエラーが発生しました。"),
|
|
MDR_DIALECT_CHOICE ("Sorry","了解")))->Go();
|
|
}
|
|
|
|
|
|
//====================================================================
|
|
// #pragma mark -
|
|
|
|
|
|
TSignatureView::TSignatureView(BRect rect)
|
|
: BBox(rect, "SigView", B_FOLLOW_ALL, B_WILL_DRAW)
|
|
{
|
|
}
|
|
|
|
|
|
void
|
|
TSignatureView::AttachedToWindow()
|
|
{
|
|
BRect rect = Bounds();
|
|
float name_text_length = StringWidth(kNameText);
|
|
float sig_text_length = StringWidth(kSigText);
|
|
float divide_length;
|
|
|
|
if (name_text_length > sig_text_length)
|
|
divide_length = name_text_length;
|
|
else
|
|
divide_length = sig_text_length;
|
|
|
|
rect.InsetBy(8,0);
|
|
rect.top+= 8;
|
|
|
|
fName = new TNameControl(rect, kNameText, new BMessage(NAME_FIELD));
|
|
AddChild(fName);
|
|
|
|
fName->SetDivider(divide_length + 10);
|
|
fName->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
|
|
|
|
rect.OffsetBy(0,fName->Bounds().Height()+5);
|
|
rect.bottom = rect.top + kSigHeight;
|
|
rect.left = fName->TextView()->Frame().left;
|
|
|
|
BRect text = rect;
|
|
text.OffsetTo(10,0);
|
|
fTextView = new TSigTextView(rect, text);
|
|
BScrollView *scroller = new BScrollView("SigScroller", fTextView, B_FOLLOW_ALL, 0, false, true);
|
|
AddChild(scroller);
|
|
scroller->ResizeBy(-1 * scroller->ScrollBar(B_VERTICAL)->Frame().Width() - 9, 0);
|
|
scroller->MoveBy(7,0);
|
|
|
|
/* back up a bit to make room for the label */
|
|
|
|
rect = scroller->Frame();
|
|
BStringView *stringView = new BStringView(rect, "SigLabel", kSigText);
|
|
AddChild(stringView);
|
|
|
|
float tWidth, tHeight;
|
|
stringView->GetPreferredSize(&tWidth, &tHeight);
|
|
|
|
/* the 5 is for the spacer in the TextView */
|
|
|
|
rect.OffsetBy(-1 *(tWidth) - 5, 0);
|
|
rect.right = rect.left + tWidth;
|
|
rect.bottom = rect.top + tHeight;
|
|
|
|
stringView->MoveTo(rect.LeftTop());
|
|
stringView->ResizeTo(rect.Width(), rect.Height());
|
|
|
|
/* Resize the View to the correct height */
|
|
scroller->SetResizingMode(B_FOLLOW_NONE);
|
|
ResizeTo(Frame().Width(), scroller->Frame().bottom + 8);
|
|
scroller->SetResizingMode(B_FOLLOW_ALL);
|
|
}
|
|
|
|
|
|
//====================================================================
|
|
// #pragma mark -
|
|
|
|
|
|
TNameControl::TNameControl(BRect rect, const char *label, BMessage *msg)
|
|
:BTextControl(rect, "", label, "", msg, B_FOLLOW_LEFT_RIGHT)
|
|
{
|
|
strcpy(fLabel, label);
|
|
}
|
|
|
|
|
|
void
|
|
TNameControl::AttachedToWindow()
|
|
{
|
|
BTextControl::AttachedToWindow();
|
|
|
|
SetDivider(StringWidth(fLabel) + 6);
|
|
TextView()->SetMaxBytes(B_FILE_NAME_LENGTH - 1);
|
|
}
|
|
|
|
|
|
void
|
|
TNameControl::MessageReceived(BMessage *msg)
|
|
{
|
|
switch (msg->what) {
|
|
case M_SELECT:
|
|
TextView()->Select(0, TextView()->TextLength());
|
|
break;
|
|
|
|
default:
|
|
BTextControl::MessageReceived(msg);
|
|
}
|
|
}
|
|
|
|
|
|
//====================================================================
|
|
// #pragma mark -
|
|
|
|
|
|
TSigTextView::TSigTextView(BRect frame, BRect text)
|
|
:BTextView(frame, "SignatureView", text, B_FOLLOW_ALL, B_NAVIGABLE | B_WILL_DRAW)
|
|
{
|
|
fDirty = false;
|
|
SetDoesUndo(true);
|
|
}
|
|
|
|
|
|
void
|
|
TSigTextView::FrameResized(float /*width*/, float /*height*/)
|
|
{
|
|
BRect r(Bounds());
|
|
r.InsetBy(3, 3);
|
|
SetTextRect(r);
|
|
}
|
|
|
|
|
|
void
|
|
TSigTextView::DeleteText(int32 offset, int32 len)
|
|
{
|
|
fDirty = true;
|
|
BTextView::DeleteText(offset, len);
|
|
}
|
|
|
|
|
|
void
|
|
TSigTextView::InsertText(const char *text, int32 len, int32 offset,
|
|
const text_run_array *runs)
|
|
{
|
|
fDirty = true;
|
|
BTextView::InsertText(text, len, offset, runs);
|
|
}
|
|
|
|
|
|
void
|
|
TSigTextView::KeyDown(const char *key, int32 count)
|
|
{
|
|
bool up = false;
|
|
int32 height;
|
|
BRect r;
|
|
|
|
switch (key[0]) {
|
|
case B_HOME:
|
|
Select(0, 0);
|
|
ScrollToSelection();
|
|
break;
|
|
|
|
case B_END:
|
|
Select(TextLength(), TextLength());
|
|
ScrollToSelection();
|
|
break;
|
|
|
|
case B_PAGE_UP:
|
|
up = true;
|
|
case B_PAGE_DOWN:
|
|
r = Bounds();
|
|
height = (int32)((up ? r.top - r.bottom : r.bottom - r.top) - 25);
|
|
if ((up) && (!r.top))
|
|
break;
|
|
ScrollBy(0, height);
|
|
break;
|
|
|
|
default:
|
|
BTextView::KeyDown(key, count);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
TSigTextView::MessageReceived(BMessage *msg)
|
|
{
|
|
char type[B_FILE_NAME_LENGTH];
|
|
char *text;
|
|
int32 end;
|
|
int32 start;
|
|
BFile file;
|
|
BNodeInfo *node;
|
|
entry_ref ref;
|
|
off_t size;
|
|
|
|
switch (msg->what) {
|
|
case B_SIMPLE_DATA:
|
|
if (msg->HasRef("refs")) {
|
|
msg->FindRef("refs", &ref);
|
|
file.SetTo(&ref, O_RDONLY);
|
|
if (file.InitCheck() == B_NO_ERROR) {
|
|
node = new BNodeInfo(&file);
|
|
node->GetType(type);
|
|
delete node;
|
|
file.GetSize(&size);
|
|
if ((!strncasecmp(type, "text/", 5)) && (size)) {
|
|
text = (char *)malloc(size);
|
|
file.Read(text, size);
|
|
Delete();
|
|
GetSelection(&start, &end);
|
|
Insert(text, size);
|
|
Select(start, start + size);
|
|
free(text);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
BTextView::MessageReceived(msg);
|
|
break;
|
|
|
|
case M_SELECT:
|
|
if (IsSelectable())
|
|
Select(0, TextLength());
|
|
break;
|
|
|
|
default:
|
|
BTextView::MessageReceived(msg);
|
|
}
|
|
}
|
|
|