/**** ファイル名 : BTinyEditor.h ****/
#ifndef BTINYEDITORAPP #define BTINYEDITORAPP //--------------------------------------------------------------------- #include <Be.h> #include "MainWindow.h" //--------------------------------------------------------------------- #define APPLICATION_SIGNATURE "application/x-vnd.vow-betinyeditor" //--------------------------------------------------------------------- class BTinyEditorApp : public BApplication { private: BFilePanel *open_filepanel; public: BTinyEditorApp(); ~BTinyEditorApp(); void MessageReceived(BMessage *msg); void RefsReceived(BMessage *message); }; //--------------------------------------------------------------------- #endif
/**** ファイル名 : BTinyEditor.cpp ****/
//--------------------------------------------------------------------- #include "BTinyEditor.h" #include <Be.h> //--------------------------------------------------------------------- BTinyEditorApp::BTinyEditorApp() :BApplication(APPLICATION_SIGNATURE) { BEditorWindow *mainwnd=new BEditorWindow( BRect(MAINWINDOW_POSITION_LEFT,MAINWINDOW_POSITION_TOP, MAINWINDOW_POSITION_WIDTH+MAINWINDOW_POSITION_LEFT-1, MAINWINDOW_POSITION_HEIGHT+MAINWINDOW_POSITION_TOP-1), MAINWINDOW_TITLE); open_filepanel= new BFilePanel(); mainwnd->Show(); } //--------------------------------------------------------------------- BTinyEditorApp::~BTinyEditorApp() { delete open_filepanel; } //--------------------------------------------------------------------- void BTinyEditorApp::MessageReceived(BMessage *msg) { switch(msg->what) { case MSG_OPEN: open_filepanel->Show(); break; default: BApplication::MessageReceived(msg); } } //--------------------------------------------------------------------- void BTinyEditorApp::RefsReceived(BMessage *message) { type_code ref_type; int32 ref_count; entry_ref ref; BEntry entry; message->GetInfo("refs", &ref_type,&ref_count); for (int i=0;i<ref_count;i++) { message->FindRef("refs",i,&ref); if(entry.SetTo(&ref)==B_OK) { WindowAt(0)->Lock(); ((BEditorWindow *)WindowAt(0))->OpenFile(&entry); WindowAt(0)->Unlock(); return; } } } //---------------------------------------------------------------------
/**** ファイル名 : BTinyEditor.h ****/
#ifndef BTINYEDITORAPP #define BTINYEDITORAPP //--------------------------------------------------------------------- #include <Be.h> #include "MainWindow.h" //--------------------------------------------------------------------- #define APPLICATION_SIGNATURE "application/x-vnd.vow-betinyeditor" //--------------------------------------------------------------------- class BTinyEditorApp : public BApplication { private: BList *EditorList; BFilePanel *open_filepanel; public: BTinyEditorApp(); ~BTinyEditorApp(); BEditorWindow *AddEditor(void); void MessageReceived(BMessage *msg); void RefsReceived(BMessage *message); }; //--------------------------------------------------------------------- #endif
/**** ファイル名 : BTinyEditor.cpp ****/
//--------------------------------------------------------------------- #include "BTinyEditor.h" #include <Be.h> //--------------------------------------------------------------------- BTinyEditorApp::BTinyEditorApp() :BApplication(APPLICATION_SIGNATURE) { EditorList=new BList(); open_filepanel= new BFilePanel(); AddEditor(); } //--------------------------------------------------------------------- BTinyEditorApp::~BTinyEditorApp() { delete open_filepanel; for(int i=EditorList->CountItems()-1;i>=0;i--) { BEditorWindow *targetwnd= ((BEditorWindow *)EditorList->ItemAt(i)); targetwnd->Quit(); EditorList->RemoveItem(targetwnd); } delete EditorList; } //--------------------------------------------------------------------- BEditorWindow *BTinyEditorApp::AddEditor(void) { BEditorWindow *mainwnd=new BEditorWindow( BRect(MAINWINDOW_POSITION_LEFT,MAINWINDOW_POSITION_TOP, MAINWINDOW_POSITION_WIDTH+MAINWINDOW_POSITION_LEFT-1, MAINWINDOW_POSITION_HEIGHT+MAINWINDOW_POSITION_TOP-1), MAINWINDOW_TITLE); EditorList->AddItem((void *)mainwnd); mainwnd->Show(); return mainwnd; } //--------------------------------------------------------------------- void BTinyEditorApp::MessageReceived(BMessage *msg) { switch(msg->what) { case MSG_OPEN: open_filepanel->Show(); break; default: BApplication::MessageReceived(msg); } } //--------------------------------------------------------------------- void BTinyEditorApp::RefsReceived(BMessage *message) { type_code ref_type; int32 ref_count; entry_ref ref; BEntry entry; message->GetInfo("refs", &ref_type,&ref_count); for (int i=0;i<ref_count;i++) { message->FindRef("refs",i,&ref); if(entry.SetTo(&ref)==B_OK) { ((BEditorWindow *)EditorList->ItemAt(0))->Lock(); ((BEditorWindow *)EditorList->ItemAt(0))->OpenFile(&entry); ((BEditorWindow *)EditorList->ItemAt(0))->Unlock(); return; } } } //---------------------------------------------------------------------
| 発行元クラス | 処理クラス | メッセージ | 処理 |
|---|---|---|---|
| BEditorWindow | BTinyEditorApp | MSG_OPEN | オープン用のファイルパネルを開く。 |
| - | BTinyEditorApp | B_REFS_RECEIVED | ウィンドウを追加。メッセージからオープンするファイル情報を取得し、追加したウィンドウのOpenFile関数を呼び出す。 |
| BEditorWindow | BTinyEditorApp | MSG_ADDEDITOR | ウィンドウを追加する。 |
| BEditorWindow | BEditorWindow | MSG_SAVE | ファイル名が設定されているかを調べ、設定されていればファイルを上書き保存する。設定されていなければ、MSG_SAVEASの処理を行う。 |
| BEditorWindow | BEditorWindow | MSG_SAVEAS | 保存用のファイルパネルを開く。 |
| - | BEditorWindow | B_SAVE_REQUESTED | メッセージから保存先のファイル情報を取得し、SaveFile関数を呼び出す。 |
| - | BEditorWindow | B_QUIT_REQUESTED |
ファイルが保存済みかを確認。保存済みでなければ、保存確認メッセージを表示し、必要に応じてMSG_SAVEメッセージを発行。 ファイルが保存済みであるか、保存確認メッセージで「Don't Save」を選択した場合は、ウィンドウの終了を許可し、BTinyEditorAppクラスにMSG_CLOSEDメッセージを発行する。MSG_CLOSEDメッセージには自分自身のポインタを付加しておく。 |
| BEditorWindow | BTinyEditorApp | MSG_CLOSED |
メッセージから終了したウィンドウを取得し、リストからそのウィンドウを削除する。 リストの登録数が0になったら、自分自身にB_QUIT_REQUESTEDメッセージを発行する。 |
| - | BTinyEditorApp | B_QUIT_REQUESTED | 作成したクラスの実体を削除し、アプリケーションを終了する。 |
| BEditorWindow | BTinyEditorApp | MSG_QUIT | 開いているすべてのウィンドウにB_QUIT_REQUESTEDメッセージを発行する。 |
/**** ファイル名 : BTinyEditor.cpp ****/
//--------------------------------------------------------------------- void BTinyEditorApp::MessageReceived(BMessage *msg) { switch(msg->what) { case MSG_OPEN: open_filepanel->Show(); break; case MSG_QUIT: for(int i=EditorList->CountItems()-1;i>=0;i--) ((BEditorWindow *)EditorList->ItemAt(i))-> PostMessage(B_QUIT_REQUESTED); break; case MSG_CLOSED: { BEditorWindow *targetwnd; msg->FindPointer("wnd",(void **)&targetwnd); if(targetwnd!=NULL) { targetwnd->Quit(); EditorList->RemoveItem(targetwnd); if(EditorList->CountItems()==0) PostMessage(B_QUIT_REQUESTED); } } break; case MSG_ADDEDITOR: AddEditor(); break; default: BApplication::MessageReceived(msg); } } //--------------------------------------------------------------------- void BTinyEditorApp::RefsReceived(BMessage *message) { type_code ref_type; int32 ref_count; entry_ref ref; BEntry entry; message->GetInfo("refs", &ref_type,&ref_count); for(int i=0;i<ref_count;i++) { message->FindRef("refs",i,&ref); if(entry.SetTo(&ref)==B_OK) { if(entry.IsFile()) { BEditorWindow *targetwnd; targetwnd=AddEditor(); targetwnd->Lock(); targetwnd->OpenFile(&entry); targetwnd->Unlock(); } } } } //--------------------------------------------------------------------- void BTinyEditorApp::ReadyToRun() { if(EditorList->CountItems()==0) AddEditor(); } //---------------------------------------------------------------------
の追加と、BEditorWindowクラスの定義に#define MSG_CLOSED 'mcld' #define MSG_QUIT 'mqit' #define MSG_ADDEDITOR 'madd'
class BEditorWindow : public BWindow
{
private:
BFilePanel *save_filepanel;
bool save_to_quit;
void SetFileName(BEntry *entry);
public:
BPath *editingpath;
BEditorView *mainview;
//-----------------------------------------------------------------
editingpathが追加されています。editingpathは、編集中のファイルのパスを保存するために使用します。save_to_quitについては、後で説明します。
BMenu *filemenu=new BMenu("File");
filemenu->AddItem(new BMenuItem("Open...",new BMessage(MSG_OPEN)));
filemenu->ItemAt(0)->SetTarget(be_app);
filemenu->AddItem(new BMenuItem("New Text",new BMessage(MSG_ADDEDITOR)));
filemenu->ItemAt(1)->SetTarget(be_app);
filemenu->AddItem(new BMenuItem("Save",new BMessage(MSG_SAVE)));
filemenu->ItemAt(2)->Message()->AddBool("to_quit",false);
filemenu->AddItem(new BMenuItem("Save As...",new BMessage(MSG_SAVEAS)));
filemenu->ItemAt(3)->Message()->AddBool("to_quit",false);
filemenu->AddSeparatorItem();
filemenu->AddItem(new BMenuItem("Close",new BMessage(B_QUIT_REQUESTED)));
filemenu->AddSeparatorItem();
filemenu->AddItem(new BMenuItem("Quit",new BMessage(MSG_QUIT)));
filemenu->ItemAt(7)->SetTarget(be_app);
mainmenu->AddItem(filemenu);
MSG_ADDEDITORメッセージを発行する「New Text」が追加されています。メッセージの送信先はbe_app、つまりBTinyEditorAppクラスになっています。/**** ファイル名 : BMemoView.h ****/
#ifndef BMEMOVIEW #define BMEMOVIEW //--------------------------------------------------------------------- #include <Be.h> //--------------------------------------------------------------------- class BMemoView : public BTextView { public: bool Modified; BMemoView(BRect frame,const char *name,uint32 resizingMode); void MessageReceived(BMessage *msg); void KeyDown(const char *bytes,int32 numBytes); }; //--------------------------------------------------------------------- #endif
/**** ファイル名 : BMemoView.cpp ****/
//--------------------------------------------------------------------- #include "BMemoView.h" //--------------------------------------------------------------------- BMemoView::BMemoView(BRect frame,const char *name,uint32 resizingMode) :BTextView(frame,name,BRect(0,0,frame.Width(),frame.Height()), resizingMode,B_WILL_DRAW) { Modified=false; } //--------------------------------------------------------------------- void BMemoView::MessageReceived(BMessage *msg) { switch(msg->what) { case B_UNDO: case B_COPY: case B_CUT: case B_PASTE: Modified=true; default: BTextView::MessageReceived(msg); } } //--------------------------------------------------------------------- void BMemoView::KeyDown(const char *bytes,int32 numBytes) { switch(*bytes) { case B_LEFT_ARROW: case B_RIGHT_ARROW: case B_UP_ARROW: case B_DOWN_ARROW: case B_INSERT: case B_HOME: case B_END: case B_PAGE_UP: case B_PAGE_DOWN: case B_FUNCTION_KEY: break; default: Modified=true; } BTextView::KeyDown(bytes,numBytes); } //---------------------------------------------------------------------
//---------------------------------------------------------------------
bool BEditorWindow::QuitRequested()
{
BMemoView *memo;
bool result;
memo=((BMemoView *)FindView("memo"));
result=false;
if(memo!=NULL)
{
if(memo->Modified)
{
char m[1024];
int32 idx;
BAlert *wrnmsg;
sprintf(m,"Save changes to the document \"%s\"?",
(editingpath!=NULL)?editingpath->Leaf():"Untitled");
wrnmsg=new BAlert("Warning!!", m,
"Cancel","Don't save","Save",
B_WIDTH_AS_USUAL,B_OFFSET_SPACING,
B_WARNING_ALERT);
wrnmsg->SetShortcut(0,B_ESCAPE);
idx=wrnmsg->Go();
if(idx==0)
return false;
if(idx==2)
{
BMessage *msg=new BMessage(MSG_SAVE);
msg->AddBool("to_quit",true);
PostMessage(msg);
return false;
}
}
}
BMessage *msg_closed=new BMessage(MSG_CLOSED);
msg_closed->AddPointer("wnd",this);
be_app->PostMessage(msg_closed);
return true;
};
//---------------------------------------------------------------------
BMemoViewクラスのModified変数を調べ、trueならば、BAlertクラスで保存するか否かを確認します。「Cancel」が選択された場合は、falseを返して関数を終了します。QuitRequested関数の戻り値としてfalseを設定すると、ウィンドウの終了処理が中断されます。
//---------------------------------------------------------------------
void BEditorWindow::MessageReceived(BMessage *msg)
{
switch(msg->what)
{
case B_UNDO:
case B_COPY:
case B_CUT:
case B_PASTE:
case B_SELECT_ALL:
((BMemoView *)FindView("memo"))->MessageReceived(msg);
break;
case MSG_SAVE:
msg->FindBool("to_quit",&save_to_quit);
if(editingpath!=NULL)
{
BEntry entry;
entry.SetTo(editingpath->Path());
SaveFile(&entry);
break;
}
case MSG_SAVEAS:
msg->FindBool("to_quit",&save_to_quit);
save_filepanel->SetTarget(this);
save_filepanel->Show();
break;
case B_SAVE_REQUESTED:
{
entry_ref ref;
BString nam;
BDirectory dir;
BEntry entry;
msg->FindRef("directory",&ref);
msg->FindString("name",&nam);
dir.SetTo(&ref);
if(entry.SetTo(&dir,nam.String())==B_OK)
{
SaveFile(&entry);
return;
}
}
break;
default:
BWindow::MessageReceived(msg);
}
}
//---------------------------------------------------------------------
void BEditorWindow::SaveFile(BEntry *entry)
{
BFile fil;
off_t wsize;
off_t tsize;
try
{
fil.SetTo(entry,B_READ_WRITE | B_CREATE_FILE);
tsize=strlen(((BTextView *)FindView("memo"))->Text());
wsize=fil.WriteAt(0,((BTextView *)FindView("memo"))->Text(),
tsize);
if(tsize==wsize)
{
SetFileName(entry);
if(save_to_quit)
PostMessage(new BMessage(B_QUIT_REQUESTED));
}
}
catch(...)
{
BAlert *altmsg = new BAlert("Error", "File write failed!!","OK",
NULL,NULL,B_WIDTH_AS_USUAL,
B_WARNING_ALERT);
altmsg->Go();
}
}
//---------------------------------------------------------------------
SaveFile関数では、保存が正常に終了した場合、save_to_quitの値を調べて、trueならばB_QUIT_REQUESTEDメッセージを発行します。
//---------------------------------------------------------------------
void BEditorWindow::SetFileName(BEntry *entry)
{
if(editingpath==NULL)
editingpath=new BPath();
entry->GetPath(editingpath);
if(editingpath!=NULL)
{
char nam[B_FILE_NAME_LENGTH];
entry->GetName(nam);
SetTitle(nam);
}
((BMemoView *)FindView("memo"))->Modified=false;
}
//---------------------------------------------------------------------
| 圧縮ファイル R5 Intel環境で確認 |
BTinyEditor20000530.zip |
| ソースファイル | BTinyEditor.cpp |
| BTinyEditor.h | |
| BMemoView.cpp | |
| BMemoView.h | |
| main.cpp | |
| MainWindow.cpp | |
| MainWindow.h |