haiku/src/apps/text_search/Model.cpp

329 lines
6.8 KiB
C++

/*
* Copyright (c) 1998-2007 Matthijs Hollemans
* Distributed under the terms of the MIT License.
*/
#include "Model.h"
#include <new>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <FindDirectory.h>
#include <List.h>
#include <MenuItem.h>
#include <Path.h>
#include <Roster.h>
#include "GlobalDefs.h"
using std::nothrow;
Model::Model()
:
fDirectory(),
fSelectedFiles((uint32)0),
fRecurseDirs(true),
fRecurseLinks(false),
fSkipDotDirs(true),
fCaseSensitive(false),
fRegularExpression(false),
fTextOnly(true),
fInvokeEditor(false),
fFrame(100, 100, 500, 400),
fState(STATE_IDLE),
fFilePanelPath(""),
fShowLines(true),
fEncoding(0)
{
BPath path;
if (find_directory(B_USER_DIRECTORY, &path) == B_OK)
fFilePanelPath = path.Path();
else
fFilePanelPath = "/boot/home";
}
status_t
Model::LoadPrefs()
{
BFile file;
status_t status = _OpenFile(&file, PREFS_FILE);
if (status != B_OK)
return status;
status = file.Lock();
if (status != B_OK)
return status;
int32 value;
if (file.ReadAttr("RecurseDirs", B_INT32_TYPE, 0, &value,
sizeof(int32)) > 0)
fRecurseDirs = (value != 0);
if (file.ReadAttr("RecurseLinks", B_INT32_TYPE, 0, &value,
sizeof(int32)) > 0)
fRecurseLinks = (value != 0);
if (file.ReadAttr("SkipDotDirs", B_INT32_TYPE, 0, &value,
sizeof(int32)) > 0)
fSkipDotDirs = (value != 0);
if (file.ReadAttr("CaseSensitive", B_INT32_TYPE, 0, &value,
sizeof(int32)) > 0)
fCaseSensitive = (value != 0);
if (file.ReadAttr("RegularExpression", B_INT32_TYPE, 0, &value,
sizeof(int32)) > 0)
fRegularExpression = (value != 0);
if (file.ReadAttr("TextOnly", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0)
fTextOnly = (value != 0);
if (file.ReadAttr("InvokeEditor", B_INT32_TYPE, 0, &value, sizeof(int32))
> 0)
fInvokeEditor = (value != 0);
char buffer [B_PATH_NAME_LENGTH+1];
int32 length = file.ReadAttr("FilePanelPath", B_STRING_TYPE, 0, &buffer,
sizeof(buffer));
if (length > 0) {
buffer[length] = '\0';
fFilePanelPath = buffer;
}
file.ReadAttr("WindowFrame", B_RECT_TYPE, 0, &fFrame, sizeof(BRect));
if (file.ReadAttr("ShowLines", B_INT32_TYPE, 0, &value,
sizeof(int32)) > 0)
fShowLines = (value != 0);
if (file.ReadAttr("Encoding", B_INT32_TYPE, 0, &value, sizeof(int32)) > 0)
fEncoding = value;
file.Unlock();
return B_OK;
}
status_t
Model::SavePrefs()
{
BFile file;
status_t status = _OpenFile(&file, PREFS_FILE,
B_CREATE_FILE | B_WRITE_ONLY);
if (status != B_OK)
return status;
status = file.Lock();
if (status != B_OK)
return status;
int32 value = 2;
file.WriteAttr("Version", B_INT32_TYPE, 0, &value, sizeof(int32));
value = fRecurseDirs ? 1 : 0;
file.WriteAttr("RecurseDirs", B_INT32_TYPE, 0, &value, sizeof(int32));
value = fRecurseLinks ? 1 : 0;
file.WriteAttr("RecurseLinks", B_INT32_TYPE, 0, &value, sizeof(int32));
value = fSkipDotDirs ? 1 : 0;
file.WriteAttr("SkipDotDirs", B_INT32_TYPE, 0, &value, sizeof(int32));
value = fCaseSensitive ? 1 : 0;
file.WriteAttr("CaseSensitive", B_INT32_TYPE, 0, &value, sizeof(int32));
value = fRegularExpression ? 1 : 0;
file.WriteAttr("RegularExpression", B_INT32_TYPE, 0, &value, sizeof(int32));
value = fTextOnly ? 1 : 0;
file.WriteAttr("TextOnly", B_INT32_TYPE, 0, &value, sizeof(int32));
value = fInvokeEditor ? 1 : 0;
file.WriteAttr("InvokeEditor", B_INT32_TYPE, 0, &value, sizeof(int32));
file.WriteAttr("WindowFrame", B_RECT_TYPE, 0, &fFrame, sizeof(BRect));
file.WriteAttr("FilePanelPath", B_STRING_TYPE, 0, fFilePanelPath.String(),
fFilePanelPath.Length() + 1);
value = fShowLines ? 1 : 0;
file.WriteAttr("ShowLines", B_INT32_TYPE, 0, &value, sizeof(int32));
file.WriteAttr("Encoding", B_INT32_TYPE, 0, &fEncoding, sizeof(int32));
file.Sync();
file.Unlock();
return B_OK;
}
void
Model::AddToHistory(const char* text)
{
BList items;
_LoadHistory(items);
BString* string = new (nothrow) BString(text);
if (string == NULL || !items.AddItem(string)) {
delete string;
_FreeHistory(items);
return;
}
int32 count = items.CountItems() - 1;
// don't check last item, since that's the one we just added
for (int32 t = 0; t < count; ++t) {
// If the same text is already in the list,
// then remove it first. Case-sensitive.
BString* string = static_cast<BString*>(items.ItemAt(t));
if (*string == text) {
delete static_cast<BString*>(items.RemoveItem(t));
break;
}
}
while (items.CountItems() >= HISTORY_LIMIT)
delete static_cast<BString*>(items.RemoveItem((int32)0));
_SaveHistory(items);
_FreeHistory(items);
}
void
Model::FillHistoryMenu(BMenu* menu) const
{
BList items;
if (!_LoadHistory(items))
return;
for (int32 t = items.CountItems() - 1; t >= 0; --t) {
BString* item = static_cast<BString*>(items.ItemAtFast(t));
BMessage* message = new BMessage(MSG_SELECT_HISTORY);
message->AddString("text", item->String());
menu->AddItem(new BMenuItem(item->String(), message));
}
_FreeHistory(items);
}
// #pragma mark - private
bool
Model::_LoadHistory(BList& items) const
{
BFile file;
status_t status = _OpenFile(&file, PREFS_FILE);
if (status != B_OK)
return false;
status = file.Lock();
if (status != B_OK)
return false;
BMessage message;
status = message.Unflatten(&file);
if (status != B_OK)
return false;
file.Unlock();
BString string;
for (int32 x = 0; message.FindString("string", x, &string) == B_OK; x++) {
BString* copy = new (nothrow) BString(string);
if (copy == NULL || !items.AddItem(copy)) {
delete copy;
break;
}
}
return true;
}
status_t
Model::_SaveHistory(const BList& items) const
{
BFile file;
status_t status = _OpenFile(&file, PREFS_FILE,
B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE,
B_USER_SETTINGS_DIRECTORY, NULL);
if (status != B_OK)
return status;
status = file.Lock();
if (status != B_OK)
return status;
BMessage message;
int32 count = items.CountItems();
for (int32 i = 0; i < count; i++) {
BString* string = static_cast<BString*>(items.ItemAtFast(i));
if (message.AddString("string", string->String()) != B_OK)
break;
}
status = message.Flatten(&file);
file.SetSize(message.FlattenedSize());
file.Sync();
file.Unlock();
return status;
}
void
Model::_FreeHistory(const BList& items) const
{
for (int32 t = items.CountItems() - 1; t >= 0; --t)
delete static_cast<BString*>((items.ItemAtFast(t)));
}
status_t
Model::_OpenFile(BFile* file, const char* name, uint32 openMode,
directory_which which, BVolume* volume) const
{
if (file == NULL)
return B_BAD_VALUE;
BPath path;
status_t status = find_directory(which, &path, true, volume);
if (status != B_OK)
return status;
status = path.Append(PREFS_FILE);
if (status != B_OK)
return status;
status = file->SetTo(path.Path(), openMode);
if (status != B_OK)
return status;
status = file->InitCheck();
if (status != B_OK)
return status;
return B_OK;
}