Node monitoring and on-the-fly textencoding change
This work is based on the draft node monitoring implementation created by Vlad Slepukhin during GCI 2012 and includes following: * Refactoring of the document "Reload" feature - it replaces "Revert to saved" one because do the same things and a bit more. Looks like we have to keep "Reload" menu entry alive until StyledEdit will get more functional Undo/Redo features. Reload functionality is also heavily used in node monitoring and on-the-fly text encoding changing. Fixes #6887; * Support for text encoding on-the-fly switching. This make life easier for those who lives in countires with multiple popular 8-bit encodings. Russia is the sample of such de facto standards' clash (KOI-8R vs CP1251 etc.); * Node Monitoring support with alerting user in case the file size or modification time were changed. Another alert is shown in case edited file was removed or moved outside of the current volume. Moving file inside of current volume silently changes references. Choosing "Ignore" will supress new change alerts until next Reload or Save user request; * Do not nag user on quiting window with zero-length untitled document. Not a Big Deal but annoys in some cases using this editor session as temporary storage.
This commit is contained in:
@@ -25,7 +25,7 @@ const uint32 MENU_NEW = 'MFnw';
|
|||||||
const uint32 MENU_OPEN = 'MFop';
|
const uint32 MENU_OPEN = 'MFop';
|
||||||
const uint32 MENU_SAVE = 'MSav';
|
const uint32 MENU_SAVE = 'MSav';
|
||||||
const uint32 MENU_SAVEAS = 'MEsa';
|
const uint32 MENU_SAVEAS = 'MEsa';
|
||||||
const uint32 MENU_REVERT = 'MFre';
|
const uint32 MENU_RELOAD = 'MFrl';
|
||||||
const uint32 MENU_CLOSE = 'MFcl';
|
const uint32 MENU_CLOSE = 'MFcl';
|
||||||
const uint32 MENU_PAGESETUP = 'MFps';
|
const uint32 MENU_PAGESETUP = 'MFps';
|
||||||
const uint32 MENU_PRINT = 'MFpr';
|
const uint32 MENU_PRINT = 'MFpr';
|
||||||
|
|||||||
@@ -73,8 +73,11 @@ StyledEditView::SetSuppressChanges(bool suppressChanges)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
StyledEditView::GetStyledText(BPositionIO* stream)
|
StyledEditView::GetStyledText(BPositionIO* stream, const char* forceEncoding)
|
||||||
{
|
{
|
||||||
|
if (forceEncoding != NULL)
|
||||||
|
fEncoding = strcmp(forceEncoding, "auto") != 0 ? forceEncoding : "";
|
||||||
|
|
||||||
fSuppressChanges = true;
|
fSuppressChanges = true;
|
||||||
status_t result = BTranslationUtils::GetStyledText(stream, this,
|
status_t result = BTranslationUtils::GetStyledText(stream, this,
|
||||||
fEncoding.String());
|
fEncoding.String());
|
||||||
@@ -85,24 +88,25 @@ StyledEditView::GetStyledText(BPositionIO* stream)
|
|||||||
|
|
||||||
BNode* node = dynamic_cast<BNode*>(stream);
|
BNode* node = dynamic_cast<BNode*>(stream);
|
||||||
if (node != NULL) {
|
if (node != NULL) {
|
||||||
// get encoding
|
if (forceEncoding == NULL) {
|
||||||
if (node->ReadAttrString("be:encoding", &fEncoding) != B_OK) {
|
// get encoding
|
||||||
// try to read as "int32"
|
if (node->ReadAttrString("be:encoding", &fEncoding) != B_OK) {
|
||||||
int32 encoding;
|
// try to read as "int32"
|
||||||
ssize_t bytesRead = node->ReadAttr("be:encoding", B_INT32_TYPE, 0,
|
int32 encoding;
|
||||||
&encoding, sizeof(encoding));
|
ssize_t bytesRead = node->ReadAttr("be:encoding", B_INT32_TYPE, 0,
|
||||||
if (bytesRead == (ssize_t)sizeof(encoding)) {
|
&encoding, sizeof(encoding));
|
||||||
if (encoding == 65535) {
|
if (bytesRead == (ssize_t)sizeof(encoding)) {
|
||||||
fEncoding = "UTF-8";
|
if (encoding == 65535) {
|
||||||
} else {
|
fEncoding = "UTF-8";
|
||||||
const BCharacterSet* characterSet
|
} else {
|
||||||
= BCharacterSetRoster::GetCharacterSetByConversionID(encoding);
|
const BCharacterSet* characterSet
|
||||||
if (characterSet != NULL)
|
= BCharacterSetRoster::GetCharacterSetByConversionID(encoding);
|
||||||
fEncoding = characterSet->GetName();
|
if (characterSet != NULL)
|
||||||
|
fEncoding = characterSet->GetName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move those into BTranslationUtils::GetStyledText() as well?
|
// TODO: move those into BTranslationUtils::GetStyledText() as well?
|
||||||
|
|
||||||
// restore alignment
|
// restore alignment
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ class StyledEditView : public BTextView {
|
|||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
void SetSuppressChanges(bool suppressChanges);
|
void SetSuppressChanges(bool suppressChanges);
|
||||||
status_t GetStyledText(BPositionIO* stream);
|
status_t GetStyledText(BPositionIO* stream,
|
||||||
|
const char* forceEncoding = NULL);
|
||||||
status_t WriteStyledEditFile(BFile* file);
|
status_t WriteStyledEditFile(BFile* file);
|
||||||
|
|
||||||
void SetEncoding(uint32 encoding);
|
void SetEncoding(uint32 encoding);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2010, Haiku, Inc. All Rights Reserved.
|
* Copyright 2002-2012, Haiku, Inc. All Rights Reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -8,6 +8,8 @@
|
|||||||
* Philippe Saint-Pierre
|
* Philippe Saint-Pierre
|
||||||
* Jonas Sundström
|
* Jonas Sundström
|
||||||
* Ryan Leavengood
|
* Ryan Leavengood
|
||||||
|
* Vlad Slepukhin
|
||||||
|
* Sarzhuk Zharski
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -33,6 +35,7 @@
|
|||||||
#include <Menu.h>
|
#include <Menu.h>
|
||||||
#include <MenuBar.h>
|
#include <MenuBar.h>
|
||||||
#include <MenuItem.h>
|
#include <MenuItem.h>
|
||||||
|
#include <NodeMonitor.h>
|
||||||
#include <Path.h>
|
#include <Path.h>
|
||||||
#include <PrintJob.h>
|
#include <PrintJob.h>
|
||||||
#include <Rect.h>
|
#include <Rect.h>
|
||||||
@@ -107,6 +110,8 @@ StyledEditWindow::~StyledEditWindow()
|
|||||||
void
|
void
|
||||||
StyledEditWindow::Quit()
|
StyledEditWindow::Quit()
|
||||||
{
|
{
|
||||||
|
_SwitchNodeMonitor(false);
|
||||||
|
|
||||||
_SaveAttrs();
|
_SaveAttrs();
|
||||||
if (StyledEditApp* app = dynamic_cast<StyledEditApp*>(be_app))
|
if (StyledEditApp* app = dynamic_cast<StyledEditApp*>(be_app))
|
||||||
app->CloseDocument();
|
app->CloseDocument();
|
||||||
@@ -124,6 +129,9 @@ StyledEditWindow::QuitRequested()
|
|||||||
if (fClean)
|
if (fClean)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (fTextView->TextLength() == 0 && fSaveMessage == NULL)
|
||||||
|
return true;
|
||||||
|
|
||||||
BString alertText;
|
BString alertText;
|
||||||
bs_printf(&alertText,
|
bs_printf(&alertText,
|
||||||
B_TRANSLATE("Save changes to the document \"%s\"? "), Title());
|
B_TRANSLATE("Save changes to the document \"%s\"? "), Title());
|
||||||
@@ -179,8 +187,8 @@ StyledEditWindow::MessageReceived(BMessage* message)
|
|||||||
Quit();
|
Quit();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MENU_REVERT:
|
case MENU_RELOAD:
|
||||||
_RevertToSaved();
|
_ReloadDocument(message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MENU_CLOSE:
|
case MENU_CLOSE:
|
||||||
@@ -294,6 +302,10 @@ StyledEditWindow::MessageReceived(BMessage* message)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case B_NODE_MONITOR:
|
||||||
|
_HandleNodeMonitorEvent(message);
|
||||||
|
break;
|
||||||
|
|
||||||
// Font menu
|
// Font menu
|
||||||
|
|
||||||
case FONT_SIZE:
|
case FONT_SIZE:
|
||||||
@@ -485,12 +497,12 @@ StyledEditWindow::MessageReceived(BMessage* message)
|
|||||||
fRedoFlag = false;
|
fRedoFlag = false;
|
||||||
}
|
}
|
||||||
if (fClean) {
|
if (fClean) {
|
||||||
fRevertItem->SetEnabled(false);
|
|
||||||
fSaveItem->SetEnabled(fSaveMessage == NULL);
|
fSaveItem->SetEnabled(fSaveMessage == NULL);
|
||||||
} else {
|
} else {
|
||||||
fRevertItem->SetEnabled(fSaveMessage != NULL);
|
|
||||||
fSaveItem->SetEnabled(true);
|
fSaveItem->SetEnabled(true);
|
||||||
}
|
}
|
||||||
|
fReloadItem->SetEnabled(fSaveMessage != NULL);
|
||||||
|
fEncodingItem->SetEnabled(fSaveMessage != NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAVE_AS_ENCODING:
|
case SAVE_AS_ENCODING:
|
||||||
@@ -646,6 +658,21 @@ StyledEditWindow::MenusBeginning()
|
|||||||
fAlignRight->SetMarked(true);
|
fAlignRight->SetMarked(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// text encoding
|
||||||
|
const BCharacterSet* charset
|
||||||
|
= BCharacterSetRoster::GetCharacterSetByFontID(fTextView->GetEncoding());
|
||||||
|
BMenu* encodingMenu = fEncodingItem->Submenu();
|
||||||
|
if (charset != NULL && encodingMenu != NULL) {
|
||||||
|
const char* mime = charset->GetMIMEName();
|
||||||
|
BString name(charset->GetPrintName());
|
||||||
|
if (mime)
|
||||||
|
name << " (" << mime << ")";
|
||||||
|
|
||||||
|
BMenuItem* item = encodingMenu->FindItem(name);
|
||||||
|
if (item != NULL)
|
||||||
|
item->SetMarked(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -656,6 +683,8 @@ StyledEditWindow::MenusBeginning()
|
|||||||
status_t
|
status_t
|
||||||
StyledEditWindow::Save(BMessage* message)
|
StyledEditWindow::Save(BMessage* message)
|
||||||
{
|
{
|
||||||
|
_NodeMonitorSuspender nodeMonitorSuspender(this);
|
||||||
|
|
||||||
if (!message)
|
if (!message)
|
||||||
message = fSaveMessage;
|
message = fSaveMessage;
|
||||||
|
|
||||||
@@ -722,10 +751,11 @@ StyledEditWindow::Save(BMessage* message)
|
|||||||
|
|
||||||
// clear clean modes
|
// clear clean modes
|
||||||
fSaveItem->SetEnabled(false);
|
fSaveItem->SetEnabled(false);
|
||||||
fRevertItem->SetEnabled(false);
|
|
||||||
fUndoCleans = false;
|
fUndoCleans = false;
|
||||||
fRedoCleans = false;
|
fRedoCleans = false;
|
||||||
fClean = true;
|
fClean = true;
|
||||||
|
fNagOnNodeChange = true;
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -811,6 +841,11 @@ StyledEditWindow::OpenFile(entry_ref* ref)
|
|||||||
|
|
||||||
_LoadAttrs();
|
_LoadAttrs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_SwitchNodeMonitor(true, ref);
|
||||||
|
|
||||||
|
fReloadItem->SetEnabled(fSaveMessage != NULL);
|
||||||
|
fEncodingItem->SetEnabled(fSaveMessage != NULL);
|
||||||
fTextView->Select(0, 0);
|
fTextView->Select(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -841,7 +876,7 @@ StyledEditWindow::Print(const char* documentName)
|
|||||||
printJob.SetSettings(new BMessage(*fPrintSettings));
|
printJob.SetSettings(new BMessage(*fPrintSettings));
|
||||||
|
|
||||||
if (printJob.ConfigJob() != B_OK)
|
if (printJob.ConfigJob() != B_OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
delete fPrintSettings;
|
delete fPrintSettings;
|
||||||
fPrintSettings = printJob.Settings();
|
fPrintSettings = printJob.Settings();
|
||||||
@@ -890,7 +925,9 @@ StyledEditWindow::Print(const char* documentName)
|
|||||||
while (printLine <= lastLine) {
|
while (printLine <= lastLine) {
|
||||||
float currentHeight = 0;
|
float currentHeight = 0;
|
||||||
int32 firstLineOnPage = printLine;
|
int32 firstLineOnPage = printLine;
|
||||||
while (currentHeight < printableRect.Height() && printLine <= lastLine) {
|
while (currentHeight < printableRect.Height()
|
||||||
|
&& printLine <= lastLine)
|
||||||
|
{
|
||||||
currentHeight += fTextView->LineHeight(printLine);
|
currentHeight += fTextView->LineHeight(printLine);
|
||||||
if (currentHeight < printableRect.Height())
|
if (currentHeight < printableRect.Height())
|
||||||
printLine++;
|
printLine++;
|
||||||
@@ -993,6 +1030,8 @@ StyledEditWindow::_InitWindow(uint32 encoding)
|
|||||||
fWrapAround = false;
|
fWrapAround = false;
|
||||||
fBackSearch = false;
|
fBackSearch = false;
|
||||||
|
|
||||||
|
fNagOnNodeChange = true;
|
||||||
|
|
||||||
// add menubar
|
// add menubar
|
||||||
fMenuBar = new BMenuBar(BRect(0, 0, 0, 0), "menubar");
|
fMenuBar = new BMenuBar(BRect(0, 0, 0, 0), "menubar");
|
||||||
AddChild(fMenuBar);
|
AddChild(fMenuBar);
|
||||||
@@ -1043,10 +1082,11 @@ StyledEditWindow::_InitWindow(uint32 encoding)
|
|||||||
menuItem->SetShortcut('S', B_SHIFT_KEY);
|
menuItem->SetShortcut('S', B_SHIFT_KEY);
|
||||||
menuItem->SetEnabled(true);
|
menuItem->SetEnabled(true);
|
||||||
|
|
||||||
menu->AddItem(fRevertItem
|
menu->AddItem(fReloadItem
|
||||||
= new BMenuItem(B_TRANSLATE("Revert to saved" B_UTF8_ELLIPSIS),
|
= new BMenuItem(B_TRANSLATE("Reload" B_UTF8_ELLIPSIS),
|
||||||
new BMessage(MENU_REVERT)));
|
new BMessage(MENU_RELOAD), 'L'));
|
||||||
fRevertItem->SetEnabled(false);
|
fReloadItem->SetEnabled(false);
|
||||||
|
|
||||||
menu->AddItem(new BMenuItem(B_TRANSLATE("Close"),
|
menu->AddItem(new BMenuItem(B_TRANSLATE("Close"),
|
||||||
new BMessage(MENU_CLOSE), 'W'));
|
new BMessage(MENU_CLOSE), 'W'));
|
||||||
|
|
||||||
@@ -1107,7 +1147,7 @@ StyledEditWindow::_InitWindow(uint32 encoding)
|
|||||||
fFontMenu = new BMenu(B_TRANSLATE("Font"));
|
fFontMenu = new BMenu(B_TRANSLATE("Font"));
|
||||||
fMenuBar->AddItem(fFontMenu);
|
fMenuBar->AddItem(fFontMenu);
|
||||||
|
|
||||||
//"Size"-subMenu
|
// "Size"-subMenu
|
||||||
fFontSizeMenu = new BMenu(B_TRANSLATE("Size"));
|
fFontSizeMenu = new BMenu(B_TRANSLATE("Size"));
|
||||||
fFontSizeMenu->SetRadioMode(true);
|
fFontSizeMenu->SetRadioMode(true);
|
||||||
fFontMenu->AddItem(fFontSizeMenu);
|
fFontMenu->AddItem(fFontSizeMenu);
|
||||||
@@ -1210,6 +1250,9 @@ StyledEditWindow::_InitWindow(uint32 encoding)
|
|||||||
fWrapItem->SetMarked(true);
|
fWrapItem->SetMarked(true);
|
||||||
fWrapItem->SetShortcut('W', B_OPTION_KEY);
|
fWrapItem->SetShortcut('W', B_OPTION_KEY);
|
||||||
|
|
||||||
|
menu->AddItem(fEncodingItem = _MakeEncodingMenuItem());
|
||||||
|
fEncodingItem->SetEnabled(false);
|
||||||
|
|
||||||
menu->AddSeparatorItem();
|
menu->AddSeparatorItem();
|
||||||
menu->AddItem(new BMenuItem(B_TRANSLATE("Statistics" B_UTF8_ELLIPSIS),
|
menu->AddItem(new BMenuItem(B_TRANSLATE("Statistics" B_UTF8_ELLIPSIS),
|
||||||
new BMessage(SHOW_STATISTICS)));
|
new BMessage(SHOW_STATISTICS)));
|
||||||
@@ -1286,7 +1329,7 @@ StyledEditWindow::_SaveAttrs()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
StyledEditWindow::_LoadFile(entry_ref* ref)
|
StyledEditWindow::_LoadFile(entry_ref* ref, const char* forceEncoding)
|
||||||
{
|
{
|
||||||
BEntry entry(ref, true);
|
BEntry entry(ref, true);
|
||||||
// traverse an eventual link
|
// traverse an eventual link
|
||||||
@@ -1299,7 +1342,7 @@ StyledEditWindow::_LoadFile(entry_ref* ref)
|
|||||||
if (status == B_OK)
|
if (status == B_OK)
|
||||||
status = file.SetTo(&entry, B_READ_ONLY);
|
status = file.SetTo(&entry, B_READ_ONLY);
|
||||||
if (status == B_OK)
|
if (status == B_OK)
|
||||||
status = fTextView->GetStyledText(&file);
|
status = fTextView->GetStyledText(&file, forceEncoding);
|
||||||
|
|
||||||
if (status == B_ENTRY_NOT_FOUND) {
|
if (status == B_ENTRY_NOT_FOUND) {
|
||||||
// Treat non-existing files consideratley; we just want to get an
|
// Treat non-existing files consideratley; we just want to get an
|
||||||
@@ -1351,11 +1394,14 @@ StyledEditWindow::_LoadFile(entry_ref* ref)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
StyledEditWindow::_RevertToSaved()
|
StyledEditWindow::_ReloadDocument(BMessage* message)
|
||||||
{
|
{
|
||||||
entry_ref ref;
|
entry_ref ref;
|
||||||
const char* name;
|
const char* name;
|
||||||
|
|
||||||
|
if (fSaveMessage == NULL || message == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
fSaveMessage->FindRef("directory", &ref);
|
fSaveMessage->FindRef("directory", &ref);
|
||||||
fSaveMessage->FindString("name", &name);
|
fSaveMessage->FindString("name", &name);
|
||||||
|
|
||||||
@@ -1376,15 +1422,40 @@ StyledEditWindow::_RevertToSaved()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BString alertText;
|
if (!fClean) {
|
||||||
bs_printf(&alertText,
|
BString alertText;
|
||||||
B_TRANSLATE("Revert to the last version of \"%s\"? "), Title());
|
bs_printf(&alertText,
|
||||||
if (_ShowAlert(alertText, B_TRANSLATE("Cancel"), B_TRANSLATE("OK"),
|
B_TRANSLATE("\"%s\" has unsaved changes.\n"
|
||||||
"", B_WARNING_ALERT) != 1)
|
"Revert it to the last saved version? "), Title());
|
||||||
return;
|
if (_ShowAlert(alertText, B_TRANSLATE("Cancel"), B_TRANSLATE("OK"),
|
||||||
|
"", B_WARNING_ALERT) != 1)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* forceEncoding = NULL;
|
||||||
|
if (message->FindString("encoding", &forceEncoding) != B_OK) {
|
||||||
|
const BCharacterSet* charset
|
||||||
|
= BCharacterSetRoster::GetCharacterSetByFontID(
|
||||||
|
fTextView->GetEncoding());
|
||||||
|
if (charset != NULL)
|
||||||
|
forceEncoding = charset->GetName();
|
||||||
|
}
|
||||||
|
|
||||||
|
BScrollBar* vertBar = fScrollView->ScrollBar(B_VERTICAL);
|
||||||
|
float vertPos = vertBar != NULL ? vertBar->Value() : 0.f;
|
||||||
|
|
||||||
|
DisableUpdates();
|
||||||
|
|
||||||
fTextView->Reset();
|
fTextView->Reset();
|
||||||
if (_LoadFile(&ref) != B_OK)
|
|
||||||
|
status = _LoadFile(&ref, forceEncoding);
|
||||||
|
|
||||||
|
if (vertBar != NULL)
|
||||||
|
vertBar->SetValue(vertPos);
|
||||||
|
|
||||||
|
EnableUpdates();
|
||||||
|
|
||||||
|
if (status != B_OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#undef B_TRANSLATION_CONTEXT
|
#undef B_TRANSLATION_CONTEXT
|
||||||
@@ -1400,10 +1471,12 @@ StyledEditWindow::_RevertToSaved()
|
|||||||
|
|
||||||
// clear clean modes
|
// clear clean modes
|
||||||
fSaveItem->SetEnabled(false);
|
fSaveItem->SetEnabled(false);
|
||||||
fRevertItem->SetEnabled(false);
|
|
||||||
fUndoCleans = false;
|
fUndoCleans = false;
|
||||||
fRedoCleans = false;
|
fRedoCleans = false;
|
||||||
fClean = true;
|
fClean = true;
|
||||||
|
|
||||||
|
fNagOnNodeChange = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1656,7 +1729,8 @@ StyledEditWindow::_UpdateCleanUndoRedoSaveRevert()
|
|||||||
fClean = false;
|
fClean = false;
|
||||||
fUndoCleans = false;
|
fUndoCleans = false;
|
||||||
fRedoCleans = false;
|
fRedoCleans = false;
|
||||||
fRevertItem->SetEnabled(fSaveMessage != NULL);
|
fReloadItem->SetEnabled(fSaveMessage != NULL);
|
||||||
|
fEncodingItem->SetEnabled(fSaveMessage != NULL);
|
||||||
fSaveItem->SetEnabled(true);
|
fSaveItem->SetEnabled(true);
|
||||||
fUndoItem->SetLabel(B_TRANSLATE("Can't undo"));
|
fUndoItem->SetLabel(B_TRANSLATE("Can't undo"));
|
||||||
fUndoItem->SetEnabled(false);
|
fUndoItem->SetEnabled(false);
|
||||||
@@ -1686,3 +1760,234 @@ StyledEditWindow::_ShowAlert(const BString& text, const BString& label,
|
|||||||
|
|
||||||
return alert->Go();
|
return alert->Go();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BMenuItem*
|
||||||
|
StyledEditWindow::_MakeEncodingMenuItem()
|
||||||
|
{
|
||||||
|
BMenu* menu = new BMenu(B_TRANSLATE("Text encoding"));
|
||||||
|
|
||||||
|
BCharacterSetRoster roster;
|
||||||
|
BCharacterSet charset;
|
||||||
|
while (roster.GetNextCharacterSet(&charset) == B_OK) {
|
||||||
|
const char* mime = charset.GetMIMEName();
|
||||||
|
BString name(charset.GetPrintName());
|
||||||
|
|
||||||
|
if (mime)
|
||||||
|
name << " (" << mime << ")";
|
||||||
|
|
||||||
|
BMessage *message = new BMessage(MENU_RELOAD);
|
||||||
|
if (message != NULL) {
|
||||||
|
message->AddString("encoding", charset.GetName());
|
||||||
|
menu->AddItem(new BMenuItem(name, message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menu->AddSeparatorItem();
|
||||||
|
BMessage *message = new BMessage(MENU_RELOAD);
|
||||||
|
message->AddString("encoding", "auto");
|
||||||
|
menu->AddItem(new BMenuItem(B_TRANSLATE("Autodetect"), message));
|
||||||
|
|
||||||
|
menu->SetRadioMode(true);
|
||||||
|
|
||||||
|
return new BMenuItem(menu, new BMessage(MENU_RELOAD));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#undef B_TRANSLATION_CONTEXT
|
||||||
|
#define B_TRANSLATION_CONTEXT "NodeMonitorAlerts"
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledEditWindow::_ShowNodeChangeAlert(const char* name, bool removed)
|
||||||
|
{
|
||||||
|
if (!fNagOnNodeChange)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BString alertText(removed ? B_TRANSLATE("File \"%file%\" was removed by "
|
||||||
|
"another application, recover it?")
|
||||||
|
: B_TRANSLATE("File \"%file%\" was modified by "
|
||||||
|
"another application, reload it?"));
|
||||||
|
alertText.ReplaceAll("%file%", name);
|
||||||
|
|
||||||
|
if (_ShowAlert(alertText, removed ? B_TRANSLATE("Recover")
|
||||||
|
: B_TRANSLATE("Reload"), B_TRANSLATE("Ignore"), "",
|
||||||
|
B_WARNING_ALERT) == 0)
|
||||||
|
{
|
||||||
|
if (!removed) {
|
||||||
|
// supress the warning - user has already agreed
|
||||||
|
fClean = true;
|
||||||
|
BMessage msg(MENU_RELOAD);
|
||||||
|
_ReloadDocument(&msg);
|
||||||
|
} else
|
||||||
|
Save();
|
||||||
|
} else
|
||||||
|
fNagOnNodeChange = false;
|
||||||
|
|
||||||
|
fSaveItem->SetEnabled(!fClean);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledEditWindow::_HandleNodeMonitorEvent(BMessage *message)
|
||||||
|
{
|
||||||
|
int32 opcode = 0;
|
||||||
|
if (message->FindInt32("opcode", &opcode) != B_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (opcode != B_ENTRY_CREATED
|
||||||
|
&& message->FindInt64("node") != fNodeRef.node)
|
||||||
|
// bypass foreign nodes' event
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (opcode) {
|
||||||
|
case B_STAT_CHANGED:
|
||||||
|
{
|
||||||
|
int32 fields = 0;
|
||||||
|
if (message->FindInt32("fields", &fields) == B_OK
|
||||||
|
&& (fields & (B_STAT_SIZE | B_STAT_MODIFICATION_TIME)) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
const char* name = NULL;
|
||||||
|
if (fSaveMessage->FindString("name", &name) != B_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
_ShowNodeChangeAlert(name, false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_ENTRY_MOVED:
|
||||||
|
{
|
||||||
|
int32 device = 0;
|
||||||
|
int64 srcFolder = 0;
|
||||||
|
int64 dstFolder = 0;
|
||||||
|
const char* name = NULL;
|
||||||
|
if (message->FindInt32("device", &device) != B_OK
|
||||||
|
|| message->FindInt64("to directory", &dstFolder) != B_OK
|
||||||
|
|| message->FindInt64("from directory", &srcFolder) != B_OK
|
||||||
|
|| message->FindString("name", &name) != B_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
entry_ref newRef(device, dstFolder, name);
|
||||||
|
BEntry entry(&newRef);
|
||||||
|
|
||||||
|
BEntry dirEntry;
|
||||||
|
entry.GetParent(&dirEntry);
|
||||||
|
|
||||||
|
entry_ref ref;
|
||||||
|
dirEntry.GetRef(&ref);
|
||||||
|
fSaveMessage->ReplaceRef("directory", &ref);
|
||||||
|
fSaveMessage->ReplaceString("name", name);
|
||||||
|
|
||||||
|
// store previous name - it may be useful in case
|
||||||
|
// we have just moved to temporary copy of file (vim case)
|
||||||
|
const char* sourceName = NULL;
|
||||||
|
if (message->FindString("from name", &sourceName) == B_OK) {
|
||||||
|
fSaveMessage->RemoveName("org.name");
|
||||||
|
fSaveMessage->AddString("org.name", sourceName);
|
||||||
|
fSaveMessage->RemoveName("move time");
|
||||||
|
fSaveMessage->AddInt64("move time", system_time());
|
||||||
|
}
|
||||||
|
|
||||||
|
SetTitle(name);
|
||||||
|
be_roster->AddToRecentDocuments(&newRef, APP_SIGNATURE);
|
||||||
|
|
||||||
|
if (srcFolder != dstFolder) {
|
||||||
|
_SwitchNodeMonitor(false);
|
||||||
|
_SwitchNodeMonitor(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_ENTRY_REMOVED:
|
||||||
|
{
|
||||||
|
_SwitchNodeMonitor(false);
|
||||||
|
|
||||||
|
fClean = false;
|
||||||
|
|
||||||
|
// some editors like vim save files in following way:
|
||||||
|
// 1) move t.txt -> t.txt~
|
||||||
|
// 2) re-create t.txt and write data to it
|
||||||
|
// 3) remove t.txt~
|
||||||
|
// go to catch this case
|
||||||
|
int32 device = 0;
|
||||||
|
int64 directory = 0;
|
||||||
|
BString orgName;
|
||||||
|
if (fSaveMessage->FindString("org.name", &orgName) == B_OK
|
||||||
|
&& message->FindInt32("device", &device) == B_OK
|
||||||
|
&& message->FindInt64("directory", &directory) == B_OK)
|
||||||
|
{
|
||||||
|
// reuse the source name if it is not too old
|
||||||
|
bigtime_t time = fSaveMessage->FindInt64("move time");
|
||||||
|
if ((system_time() - time) < 1000000) {
|
||||||
|
entry_ref ref(device, directory, orgName);
|
||||||
|
BEntry entry(&ref);
|
||||||
|
if (entry.InitCheck() == B_OK) {
|
||||||
|
_SwitchNodeMonitor(true, &ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
fSaveMessage->ReplaceString("name", orgName);
|
||||||
|
fSaveMessage->RemoveName("org.name");
|
||||||
|
fSaveMessage->RemoveName("move time");
|
||||||
|
|
||||||
|
SetTitle(orgName);
|
||||||
|
_ShowNodeChangeAlert(orgName, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* name = NULL;
|
||||||
|
if (message->FindString("name", &name) != B_OK
|
||||||
|
&& fSaveMessage->FindString("name", &name) != B_OK)
|
||||||
|
name = "Unknown";
|
||||||
|
|
||||||
|
_ShowNodeChangeAlert(name, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StyledEditWindow::_SwitchNodeMonitor(bool on, entry_ref* ref)
|
||||||
|
{
|
||||||
|
if (!on) {
|
||||||
|
watch_node(&fNodeRef, B_STOP_WATCHING, this);
|
||||||
|
watch_node(&fFolderNodeRef, B_STOP_WATCHING, this);
|
||||||
|
fNodeRef = node_ref();
|
||||||
|
fFolderNodeRef = node_ref();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BEntry entry, folderEntry;
|
||||||
|
|
||||||
|
if (ref != NULL) {
|
||||||
|
entry.SetTo(ref, true);
|
||||||
|
entry.GetParent(&folderEntry);
|
||||||
|
|
||||||
|
} else if (fSaveMessage != NULL) {
|
||||||
|
entry_ref ref;
|
||||||
|
const char* name = NULL;
|
||||||
|
if (fSaveMessage->FindRef("directory", &ref) != B_OK
|
||||||
|
|| fSaveMessage->FindString("name", &name) != B_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BDirectory dir(&ref);
|
||||||
|
entry.SetTo(&dir, name);
|
||||||
|
folderEntry.SetTo(&ref);
|
||||||
|
|
||||||
|
} else
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (entry.InitCheck() != B_OK || folderEntry.InitCheck() != B_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
entry.GetNodeRef(&fNodeRef);
|
||||||
|
folderEntry.GetNodeRef(&fFolderNodeRef);
|
||||||
|
|
||||||
|
watch_node(&fNodeRef, B_WATCH_STAT, this);
|
||||||
|
watch_node(&fFolderNodeRef, B_WATCH_DIRECTORY, this);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2010, Haiku, Inc. All Rights Reserved.
|
* Copyright 2002-2012, Haiku, Inc. All Rights Reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -15,15 +15,15 @@
|
|||||||
#include <Window.h>
|
#include <Window.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
#include <Message.h>
|
#include <Message.h>
|
||||||
|
#include <Node.h>
|
||||||
|
|
||||||
struct entry_ref;
|
struct entry_ref;
|
||||||
|
|
||||||
|
class BFilePanel;
|
||||||
class BMenu;
|
class BMenu;
|
||||||
class BMessage;
|
|
||||||
class BMenuBar;
|
class BMenuBar;
|
||||||
class BMenuItem;
|
class BMenuItem;
|
||||||
class BFilePanel;
|
class BMessage;
|
||||||
class BScrollView;
|
class BScrollView;
|
||||||
class StyledEditView;
|
class StyledEditView;
|
||||||
|
|
||||||
@@ -52,10 +52,12 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void _InitWindow(uint32 encoding = 0);
|
void _InitWindow(uint32 encoding = 0);
|
||||||
|
BMenuItem* _MakeEncodingMenuItem();
|
||||||
void _LoadAttrs();
|
void _LoadAttrs();
|
||||||
void _SaveAttrs();
|
void _SaveAttrs();
|
||||||
status_t _LoadFile(entry_ref* ref);
|
status_t _LoadFile(entry_ref* ref,
|
||||||
void _RevertToSaved();
|
const char* forceEncoding = NULL);
|
||||||
|
void _ReloadDocument(BMessage *message);
|
||||||
bool _Search(BString searchFor, bool caseSensitive,
|
bool _Search(BString searchFor, bool caseSensitive,
|
||||||
bool wrap, bool backSearch,
|
bool wrap, bool backSearch,
|
||||||
bool scrollToOccurence = true);
|
bool scrollToOccurence = true);
|
||||||
@@ -76,6 +78,27 @@ private:
|
|||||||
const BString& label3,
|
const BString& label3,
|
||||||
alert_type type) const;
|
alert_type type) const;
|
||||||
|
|
||||||
|
// node monitoring helper
|
||||||
|
class _NodeMonitorSuspender {
|
||||||
|
StyledEditWindow *fWindow;
|
||||||
|
public:
|
||||||
|
_NodeMonitorSuspender(StyledEditWindow *w) : fWindow(w) {
|
||||||
|
fWindow->_SwitchNodeMonitor(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
~_NodeMonitorSuspender() {
|
||||||
|
fWindow->_SwitchNodeMonitor(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
friend class _NodeMonitorSuspender;
|
||||||
|
|
||||||
|
void _HandleNodeMonitorEvent(BMessage *message);
|
||||||
|
void _ShowNodeChangeAlert(const char* name,
|
||||||
|
bool removed);
|
||||||
|
void _SwitchNodeMonitor(bool on,
|
||||||
|
entry_ref* ref = NULL);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BMenuBar* fMenuBar;
|
BMenuBar* fMenuBar;
|
||||||
BMessage* fPrintSettings;
|
BMessage* fPrintSettings;
|
||||||
@@ -89,7 +112,7 @@ private:
|
|||||||
BMenuItem* fCurrentStyleItem;
|
BMenuItem* fCurrentStyleItem;
|
||||||
|
|
||||||
BMenuItem* fSaveItem;
|
BMenuItem* fSaveItem;
|
||||||
BMenuItem* fRevertItem;
|
BMenuItem* fReloadItem;
|
||||||
|
|
||||||
BMenuItem* fUndoItem;
|
BMenuItem* fUndoItem;
|
||||||
BMenuItem* fCutItem;
|
BMenuItem* fCutItem;
|
||||||
@@ -113,6 +136,7 @@ private:
|
|||||||
BMenuItem* fAlignLeft;
|
BMenuItem* fAlignLeft;
|
||||||
BMenuItem* fAlignCenter;
|
BMenuItem* fAlignCenter;
|
||||||
BMenuItem* fAlignRight;
|
BMenuItem* fAlignRight;
|
||||||
|
BMenuItem* fEncodingItem;
|
||||||
|
|
||||||
BString fStringToFind;
|
BString fStringToFind;
|
||||||
BString fReplaceString;
|
BString fReplaceString;
|
||||||
@@ -139,6 +163,10 @@ private:
|
|||||||
|
|
||||||
BFilePanel* fSavePanel;
|
BFilePanel* fSavePanel;
|
||||||
BMenu* fSavePanelEncodingMenu;
|
BMenu* fSavePanelEncodingMenu;
|
||||||
|
// node monitoring
|
||||||
|
node_ref fNodeRef;
|
||||||
|
node_ref fFolderNodeRef;
|
||||||
|
bool fNagOnNodeChange;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user