@file
#include <string.h>
#include "Platform.h"
#include "SplitVector.h"
#include "Partitioning.h"
#include "RunStyles.h"
#include "ContractionState.h"
#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif
ContractionState::ContractionState() : visible(0), expanded(0), heights(0), displayLines(0), linesInDocument(1) {
}
ContractionState::~ContractionState() {
Clear();
}
void ContractionState::EnsureData() {
if (OneToOne()) {
visible = new RunStyles();
expanded = new RunStyles();
heights = new RunStyles();
displayLines = new Partitioning(4);
InsertLines(0, linesInDocument);
}
}
void ContractionState::Clear() {
delete visible;
visible = 0;
delete expanded;
expanded = 0;
delete heights;
heights = 0;
delete displayLines;
displayLines = 0;
linesInDocument = 1;
}
int ContractionState::LinesInDoc() const {
if (OneToOne()) {
return linesInDocument;
} else {
return displayLines->Partitions() - 1;
}
}
int ContractionState::LinesDisplayed() const {
if (OneToOne()) {
return linesInDocument;
} else {
return displayLines->PositionFromPartition(LinesInDoc());
}
}
int ContractionState::DisplayFromDoc(int lineDoc) const {
if (OneToOne()) {
return lineDoc;
} else {
if (lineDoc > displayLines->Partitions())
lineDoc = displayLines->Partitions();
return displayLines->PositionFromPartition(lineDoc);
}
}
int ContractionState::DocFromDisplay(int lineDisplay) const {
if (OneToOne()) {
return lineDisplay;
} else {
if (lineDisplay <= 0) {
return 0;
}
if (lineDisplay > LinesDisplayed()) {
return displayLines->PartitionFromPosition(LinesDisplayed());
}
int lineDoc = displayLines->PartitionFromPosition(lineDisplay);
PLATFORM_ASSERT(GetVisible(lineDoc));
return lineDoc;
}
}
void ContractionState::InsertLine(int lineDoc) {
if (OneToOne()) {
linesInDocument++;
} else {
visible->InsertSpace(lineDoc, 1);
visible->SetValueAt(lineDoc, 1);
expanded->InsertSpace(lineDoc, 1);
expanded->SetValueAt(lineDoc, 1);
heights->InsertSpace(lineDoc, 1);
heights->SetValueAt(lineDoc, 1);
int lineDisplay = DisplayFromDoc(lineDoc);
displayLines->InsertPartition(lineDoc, lineDisplay);
displayLines->InsertText(lineDoc, 1);
}
}
void ContractionState::InsertLines(int lineDoc, int lineCount) {
for (int l = 0; l < lineCount; l++) {
InsertLine(lineDoc + l);
}
Check();
}
void ContractionState::DeleteLine(int lineDoc) {
if (OneToOne()) {
linesInDocument--;
} else {
if (GetVisible(lineDoc)) {
displayLines->InsertText(lineDoc, -heights->ValueAt(lineDoc));
}
displayLines->RemovePartition(lineDoc);
visible->DeleteRange(lineDoc, 1);
expanded->DeleteRange(lineDoc, 1);
heights->DeleteRange(lineDoc, 1);
}
}
void ContractionState::DeleteLines(int lineDoc, int lineCount) {
for (int l = 0; l < lineCount; l++) {
DeleteLine(lineDoc);
}
Check();
}
bool ContractionState::GetVisible(int lineDoc) const {
if (OneToOne()) {
return true;
} else {
if (lineDoc >= visible->Length())
return true;
return visible->ValueAt(lineDoc) == 1;
}
}
bool ContractionState::SetVisible(int lineDocStart, int lineDocEnd, bool visible_) {
if (OneToOne() && visible_) {
return false;
} else {
EnsureData();
int delta = 0;
Check();
if ((lineDocStart <= lineDocEnd) && (lineDocStart >= 0) && (lineDocEnd < LinesInDoc())) {
for (int line = lineDocStart; line <= lineDocEnd; line++) {
if (GetVisible(line) != visible_) {
int difference = visible_ ? heights->ValueAt(line) : -heights->ValueAt(line);
visible->SetValueAt(line, visible_ ? 1 : 0);
displayLines->InsertText(line, difference);
delta += difference;
}
}
} else {
return false;
}
Check();
return delta != 0;
}
}
bool ContractionState::GetExpanded(int lineDoc) const {
if (OneToOne()) {
return true;
} else {
Check();
return expanded->ValueAt(lineDoc) == 1;
}
}
bool ContractionState::SetExpanded(int lineDoc, bool expanded_) {
if (OneToOne() && expanded_) {
return false;
} else {
EnsureData();
if (expanded_ != (expanded->ValueAt(lineDoc) == 1)) {
expanded->SetValueAt(lineDoc, expanded_ ? 1 : 0);
Check();
return true;
} else {
Check();
return false;
}
}
}
int ContractionState::GetHeight(int lineDoc) const {
if (OneToOne()) {
return 1;
} else {
return heights->ValueAt(lineDoc);
}
}
bool ContractionState::SetHeight(int lineDoc, int height) {
if (OneToOne() && (height == 1)) {
return false;
} else {
EnsureData();
if (GetHeight(lineDoc) != height) {
if (GetVisible(lineDoc)) {
displayLines->InsertText(lineDoc, height - GetHeight(lineDoc));
}
heights->SetValueAt(lineDoc, height);
Check();
return true;
} else {
Check();
return false;
}
}
}
void ContractionState::ShowAll() {
int lines = LinesInDoc();
Clear();
linesInDocument = lines;
}
void ContractionState::Check() const {
#ifdef CHECK_CORRECTNESS
for (int vline = 0;vline < LinesDisplayed(); vline++) {
const int lineDoc = DocFromDisplay(vline);
PLATFORM_ASSERT(GetVisible(lineDoc));
}
for (int lineDoc = 0;lineDoc < LinesInDoc(); lineDoc++) {
const int displayThis = DisplayFromDoc(lineDoc);
const int displayNext = DisplayFromDoc(lineDoc + 1);
const int height = displayNext - displayThis;
PLATFORM_ASSERT(height >= 0);
if (GetVisible(lineDoc)) {
PLATFORM_ASSERT(GetHeight(lineDoc) == height);
} else {
PLATFORM_ASSERT(0 == height);
}
}
#endif
}