haiku/src/apps/stylededit/StyledEditApp.cpp

367 lines
7.1 KiB
C++

/*
* Copyright 2002-2016, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Mattias Sundblad
* Andrew Bachmann
* Jonas Sundström
*/
#include "Constants.h"
#include "StyledEditApp.h"
#include "StyledEditWindow.h"
#include <Alert.h>
#include <Autolock.h>
#include <Catalog.h>
#include <Locale.h>
#include <MenuBar.h>
#include <CharacterSet.h>
#include <CharacterSetRoster.h>
#include <FilePanel.h>
#include <MenuItem.h>
#include <Message.h>
#include <Path.h>
#include <Screen.h>
#include <stdio.h>
using namespace BPrivate;
static BRect sWindowRect(7, 26, 507, 426);
static float sCascadeOffset = 15;
static BPoint sTopLeft = BPoint(7, 26);
namespace
{
void
cascade()
{
BScreen screen;
BRect screenBorder = screen.Frame();
float left = sWindowRect.left + sCascadeOffset;
if (left + sWindowRect.Width() > screenBorder.right)
left = sTopLeft.x;
float top = sWindowRect.top + sCascadeOffset;
if (top + sWindowRect.Height() > screenBorder.bottom)
top = sTopLeft.y;
sWindowRect.OffsetTo(BPoint(left, top));
}
void
uncascade()
{
BScreen screen;
BRect screenBorder = screen.Frame();
float left = sWindowRect.left - sCascadeOffset;
if (left < sTopLeft.x) {
left = screenBorder.right - sWindowRect.Width() - sTopLeft.x;
left = left - ((int)left % (int)sCascadeOffset) + sTopLeft.x;
}
float top = sWindowRect.top - sCascadeOffset;
if (top < sTopLeft.y) {
top = screenBorder.bottom - sWindowRect.Height() - sTopLeft.y;
top = top - ((int)left % (int)sCascadeOffset) + sTopLeft.y;
}
sWindowRect.OffsetTo(BPoint(left, top));
}
}
// #pragma mark -
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Open_and_SaveAsPanel"
StyledEditApp::StyledEditApp()
:
BApplication(APP_SIGNATURE),
fOpenPanel(NULL)
{
B_TRANSLATE_MARK_SYSTEM_NAME_VOID("StyledEdit");
fOpenPanel = new BFilePanel();
fOpenAsEncoding = 0;
BMenuBar* menuBar
= dynamic_cast<BMenuBar*>(fOpenPanel->Window()->FindView("MenuBar"));
if (menuBar != NULL) {
fOpenPanelEncodingMenu = new BMenu(B_TRANSLATE("Encoding"));
fOpenPanelEncodingMenu->SetRadioMode(true);
menuBar->AddItem(fOpenPanelEncodingMenu);
BCharacterSetRoster roster;
BCharacterSet charset;
while (roster.GetNextCharacterSet(&charset) == B_NO_ERROR) {
BString name;
if (charset.GetFontID() == B_UNICODE_UTF8)
name = B_TRANSLATE("Default");
else
name = charset.GetPrintName();
const char* mime = charset.GetMIMEName();
if (mime != NULL) {
name.Append(" (");
name.Append(mime);
name.Append(")");
}
BMenuItem* item
= new BMenuItem(name.String(), new BMessage(OPEN_AS_ENCODING));
item->SetTarget(this);
fOpenPanelEncodingMenu->AddItem(item);
if (charset.GetFontID() == fOpenAsEncoding)
item->SetMarked(true);
}
} else
fOpenPanelEncodingMenu = NULL;
fWindowCount = 0;
fNextUntitledWindow = 1;
fBadArguments = false;
float factor = be_plain_font->Size() / 12.0f;
sCascadeOffset *= factor;
sTopLeft.x *= factor;
sTopLeft.y *= factor;
sWindowRect.left *= factor;
sWindowRect.top *= factor;
sWindowRect.right *= factor;
sWindowRect.bottom *= factor;
}
StyledEditApp::~StyledEditApp()
{
delete fOpenPanel;
}
void
StyledEditApp::MessageReceived(BMessage* message)
{
switch (message->what) {
case MENU_NEW:
OpenDocument();
break;
case MENU_OPEN:
fOpenPanel->Show();
break;
case B_SILENT_RELAUNCH:
OpenDocument();
break;
case OPEN_AS_ENCODING:
void* ptr;
if (message->FindPointer("source", &ptr) == B_OK
&& fOpenPanelEncodingMenu != NULL) {
fOpenAsEncoding = (uint32)fOpenPanelEncodingMenu->IndexOf(
(BMenuItem*)ptr);
}
break;
default:
BApplication::MessageReceived(message);
break;
}
}
void
StyledEditApp::OpenDocument()
{
new StyledEditWindow(sWindowRect, fNextUntitledWindow++, fOpenAsEncoding);
cascade();
fWindowCount++;
}
status_t
StyledEditApp::OpenDocument(entry_ref* ref, BMessage* message)
{
// traverse eventual symlink
BEntry entry(ref, true);
entry.GetRef(ref);
if (entry.IsDirectory()) {
BPath path(&entry);
fprintf(stderr,
"Can't open directory \"%s\" for editing.\n",
path.Path());
return B_ERROR;
}
BEntry parent;
entry.GetParent(&parent);
if (!entry.Exists() && !parent.Exists()) {
fprintf(stderr,
"Can't create file. Missing parent directory.\n");
return B_ERROR;
}
BWindow* window = NULL;
StyledEditWindow* document = NULL;
for (int32 index = 0; ; index++) {
window = WindowAt(index);
if (window == NULL)
break;
document = dynamic_cast<StyledEditWindow*>(window);
if (document == NULL)
continue;
if (document->IsDocumentEntryRef(ref)) {
if (document->Lock()) {
document->Activate();
document->Unlock();
if (message != NULL)
document->PostMessage(message);
return B_OK;
}
}
}
document = new StyledEditWindow(sWindowRect, ref, fOpenAsEncoding);
cascade();
if (message != NULL)
document->PostMessage(message);
fWindowCount++;
return B_OK;
}
void
StyledEditApp::CloseDocument()
{
uncascade();
fWindowCount--;
if (fWindowCount == 0) {
BAutolock lock(this);
Quit();
}
}
void
StyledEditApp::RefsReceived(BMessage* message)
{
int32 index = 0;
entry_ref ref;
while (message->FindRef("refs", index, &ref) == B_OK) {
int32 line;
if (message->FindInt32("be:line", index, &line) != B_OK)
line = -1;
int32 start, length;
if (message->FindInt32("be:selection_length", index, &length) != B_OK
|| message->FindInt32("be:selection_offset", index, &start) != B_OK)
{
start = -1;
length = -1;
}
BMessage* selection = NULL;
if (line >= 0 || (start >= 0 && length >= 0)) {
selection = new BMessage(UPDATE_LINE_SELECTION);
if (line >= 0)
selection->AddInt32("be:line", line);
if (start >= 0) {
selection->AddInt32("be:selection_offset", start);
selection->AddInt32("be:selection_length", max_c(0, length));
}
}
OpenDocument(&ref, selection);
index++;
}
}
void
StyledEditApp::ArgvReceived(int32 argc, char* argv[])
{
// If StyledEdit is already running and gets invoked again
// we need to account for a possible mismatch in current
// working directory. The paths of the new arguments are
// relative to the cwd of the invocation, if they are not
// absolute. This cwd we find as a string named "cwd" in
// the BLooper's current message.
const char* cwd = "";
BMessage* message = CurrentMessage();
if (message != NULL) {
if (message->FindString("cwd", &cwd) != B_OK)
cwd = "";
}
for (int i = 1 ; (i < argc) ; i++) {
BPath path;
if (argv[i][0] == '/') {
path.SetTo(argv[i]);
} else {
path.SetTo(cwd, argv[i]);
// patch relative paths only
}
entry_ref ref;
get_ref_for_path(path.Path(), &ref);
status_t status;
status = OpenDocument(&ref);
if (status != B_OK && IsLaunching())
fBadArguments = true;
}
}
void
StyledEditApp::ReadyToRun()
{
if (fWindowCount > 0)
return;
if (fBadArguments)
Quit();
else
OpenDocument();
}
int32
StyledEditApp::NumberOfWindows()
{
return fWindowCount;
}
// #pragma mark -
int
main(int argc, char** argv)
{
StyledEditApp styledEdit;
styledEdit.Run();
return 0;
}