⛏️ index : haiku.git

/*
 * Copyright 2002-2007, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Mattias Sundblad
 *		Andrew Bachmann
 *		Axel DΓΆrfler, axeld@pinc-software.de
 */


#include "Constants.h"
#include "StyledEditView.h"

#include <CharacterSet.h>
#include <CharacterSetRoster.h>
#include <DataIO.h>
#include <File.h>
#include <Message.h>
#include <Messenger.h>
#include <Node.h>
#include <Rect.h>
#include <TranslationUtils.h>
#include <UTF8.h>

#include <stdio.h>
#include <stdlib.h>


using namespace BPrivate;


StyledEditView::StyledEditView(BRect viewFrame, BRect textBounds,
	BHandler* handler)
	:
	BTextView(viewFrame, "textview", textBounds, NULL,
		&(fInitialColor = ui_color(B_DOCUMENT_TEXT_COLOR)),
		B_FOLLOW_ALL, B_FRAME_EVENTS | B_WILL_DRAW)
{
	SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR);
	SetLowUIColor(ViewUIColor());

	fMessenger = new BMessenger(handler);
	fSuppressChanges = false;
}


StyledEditView::~StyledEditView()
{
	delete fMessenger;
}


void
StyledEditView::FrameResized(float width, float height)
{
	BTextView::FrameResized(width, height);
}


void
StyledEditView::DeleteText(int32 start, int32 finish)
{
	if (!fSuppressChanges)
		fMessenger-> SendMessage(TEXT_CHANGED);

	BTextView::DeleteText(start, finish);
	_UpdateStatus();
}


void
StyledEditView::InsertText(const char* text, int32 length, int32 offset,
	const text_run_array* runs)
{
	if (!fSuppressChanges)
		fMessenger->SendMessage(TEXT_CHANGED);

	BTextView::InsertText(text, length, offset, runs);
	_UpdateStatus();
}


void
StyledEditView::Select(int32 start, int32 finish)
{
	fMessenger->SendMessage(start == finish ? DISABLE_ITEMS : ENABLE_ITEMS);
	BTextView::Select(start, finish);
	_UpdateStatus();
}


void
StyledEditView::Reset()
{
	fSuppressChanges = true;
	SetText("");
	fEncoding = "";
	fSuppressChanges = false;
}


void
StyledEditView::SetSuppressChanges(bool suppressChanges)
{
	fSuppressChanges = suppressChanges;
}


status_t
StyledEditView::GetStyledText(BPositionIO* stream, const char* forceEncoding)
{
	if (forceEncoding != NULL)
		fEncoding = strcmp(forceEncoding, "auto") != 0 ? forceEncoding : "";

	fSuppressChanges = true;
	status_t result = BTranslationUtils::GetStyledText(stream, this,
		fEncoding.String());
	fSuppressChanges = false;

	if (result != B_OK)
		return result;

	BNode* node = dynamic_cast<BNode*>(stream);
	if (node != NULL) {
		if (forceEncoding == NULL) {
			// get encoding
			if (node->ReadAttrString("be:encoding", &fEncoding) != B_OK) {
				// try to read as "int32"
				int32 encoding;
				ssize_t bytesRead = node->ReadAttr("be:encoding", B_INT32_TYPE, 0,
					&encoding, sizeof(encoding));
				if (bytesRead == (ssize_t)sizeof(encoding)) {
					if (encoding == 65535) {
						fEncoding = "UTF-8";
					} else {
						const BCharacterSet* characterSet
							= BCharacterSetRoster::GetCharacterSetByConversionID(encoding);
						if (characterSet != NULL)
							fEncoding = characterSet->GetName();
					}
				}
			}
		}
		// TODO: move those into BTranslationUtils::GetStyledText() as well?

		// restore alignment
		int32 align;
		ssize_t bytesRead = node->ReadAttr("alignment", 0, 0, &align, sizeof(align));
		if (bytesRead == (ssize_t)sizeof(align))
			SetAlignment((alignment)align);

		// restore wrapping
		bool wrap;
		bytesRead = node->ReadAttr("wrap", 0, 0, &wrap, sizeof(wrap));
		if (bytesRead == (ssize_t)sizeof(wrap)) {
			SetWordWrap(wrap);
			if (wrap == false) {
				BRect textRect;
				textRect = Bounds();
				textRect.OffsetTo(B_ORIGIN);
				textRect.InsetBy(TEXT_INSET, TEXT_INSET);
					// the width comes from stylededit R5. TODO: find a better way
				textRect.SetRightBottom(BPoint(1500.0, textRect.RightBottom().y));
				SetTextRect(textRect);
			}
		}
	}

	return result;
}


status_t
StyledEditView::WriteStyledEditFile(BFile* file)
{
	return BTranslationUtils::WriteStyledEditFile(this, file,
		fEncoding.String());
}


void
StyledEditView::SetEncoding(uint32 encoding)
{
	fEncoding = "";
	if (encoding == 0)
		return;

	const BCharacterSet* set 
		= BCharacterSetRoster::GetCharacterSetByFontID(encoding);

	if (set != NULL)
		fEncoding = set->GetName();
}


uint32
StyledEditView::GetEncoding() const
{
	if (fEncoding == "")
		return 0;

	const BCharacterSet* set = 
		BCharacterSetRoster::FindCharacterSetByName(fEncoding.String());
	if (set != NULL)
		return set->GetFontID();

	return 0;
}


void
StyledEditView::_UpdateStatus()
{
	int32 selStart, selFinish;
	GetSelection(&selStart, &selFinish);

	int32 line = CurrentLine();
	int32 lineStart = OffsetAt(line);

	int32 column = 1;
	int32 tabSize = (int32)ceilf(TabWidth() / StringWidth("s"));
	for (int i = lineStart; i < selStart; i++) {
		unsigned char ch = ByteAt(i);
		if ((ch & 0xC0) != 0x80) {
			if (ch == '\t')
				while (column % tabSize)
					column++;
			column++;
		}
	}

	BMessage* message = new BMessage(UPDATE_STATUS);
	message->AddInt32("line", line + 1);
	message->AddInt32("column", column);
	message->AddString("encoding", fEncoding.String());
	fMessenger->SendMessage(message);
}