* The recent files list now also preserves the case of the MIME strings.

* STL allocations are guarded by a try/catch block.
* As in RecentApps, Get() did not properly populate an error condition.
* Cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19263 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2006-11-12 17:46:34 +00:00
parent 01b06fcc52
commit fd5c02b25c
2 changed files with 177 additions and 194 deletions
+1 -1
View File
@@ -82,7 +82,7 @@ RecentApps::Add(const char *appSig, int32 appFlags)
// of recent apps // of recent apps
if (!strcasecmp(appSig, kTrackerSignature) if (!strcasecmp(appSig, kTrackerSignature)
|| !strcasecmp(appSig, kDeskbarSignature) || !strcasecmp(appSig, kDeskbarSignature)
|| (appFlags & B_ARGV_ONLY) != 0 || (appFlags & B_BACKGROUND_APP) != 0) || (appFlags & (B_ARGV_ONLY | B_BACKGROUND_APP)) != 0)
return B_OK; return B_OK;
// Remove any previous instance // Remove any previous instance
+176 -193
View File
@@ -1,31 +1,14 @@
//------------------------------------------------------------------------------ /*
// Copyright (c) 2001-2005, Haiku * Copyright 2001-2006, Haiku Inc.
// * Distributed under the terms of the MIT License.
// Permission is hereby granted, free of charge, to any person obtaining a *
// copy of this software and associated documentation files (the "Software"), * Authors:
// to deal in the Software without restriction, including without limitation * Tyler Dauwalder
// the rights to use, copy, modify, merge, publish, distribute, sublicense, * Ingo Weinhold, [email protected]
// and/or sell copies of the Software, and to permit persons to whom the * Axel Dörfler, [email protected]e
// Software is furnished to do so, subject to the following conditions: */
//
// The above copyright notice and this permission notice shall be included in //! Recently launched apps list
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: RecentEntries.cpp
// Author: Tyler Dauwalder ([email protected])
// Description: Recently launched apps list
//------------------------------------------------------------------------------
/*! \file RecentEntries.cpp
\brief RecentEntries class implementation
*/
#include "RecentEntries.h" #include "RecentEntries.h"
@@ -48,9 +31,6 @@ using namespace std;
//#define DBG(x) //#define DBG(x)
#define OUT printf #define OUT printf
//------------------------------------------------------------------------------
// recent_entry
//------------------------------------------------------------------------------
/*! \struct recent_entry /*! \struct recent_entry
@@ -64,16 +44,17 @@ using namespace std;
/*! \brief Creates a new recent_entry object. /*! \brief Creates a new recent_entry object.
*/ */
recent_entry::recent_entry(const entry_ref *ref, const char *appSig, recent_entry::recent_entry(const entry_ref *ref, const char *appSig,
uint32 index) uint32 index)
: ref(ref ? *ref : entry_ref()) :
, sig(appSig) ref(ref ? *ref : entry_ref()),
, index(index) sig(appSig),
index(index)
{ {
} }
//------------------------------------------------------------------------------
// RecentEntries // #pragma mark -
//------------------------------------------------------------------------------
/*! \class RecentEntries /*! \class RecentEntries
\brief Implements the common functionality used by the roster's recent \brief Implements the common functionality used by the roster's recent
@@ -88,7 +69,7 @@ recent_entry::recent_entry(const entry_ref *ref, const char *appSig,
signatures are case-independent. signatures are case-independent.
*/ */
// constructor
/*! \brief Creates a new list. /*! \brief Creates a new list.
The list is initially empty. The list is initially empty.
@@ -97,7 +78,7 @@ RecentEntries::RecentEntries()
{ {
} }
// destructor
/*! \brief Frees all resources associated with the object. /*! \brief Frees all resources associated with the object.
*/ */
RecentEntries::~RecentEntries() RecentEntries::~RecentEntries()
@@ -105,7 +86,7 @@ RecentEntries::~RecentEntries()
Clear(); Clear();
} }
// Add
/*! \brief Places the given entry Places the app with the given signature at the front of /*! \brief Places the given entry Places the app with the given signature at the front of
the recent apps list. the recent apps list.
@@ -124,31 +105,33 @@ RecentEntries::~RecentEntries()
status_t status_t
RecentEntries::Add(const entry_ref *ref, const char *appSig) RecentEntries::Add(const entry_ref *ref, const char *appSig)
{ {
std::string sig; if (ref == NULL || appSig == NULL)
status_t error = ref && appSig ? B_OK : B_BAD_VALUE; return B_BAD_VALUE;
if (!error) {
// Store all sigs as lowercase // Look for a previous instance of this entry
sig = BPrivate::Storage::to_lower(appSig); std::list<recent_entry*>::iterator item;
for (item = fEntryList.begin(); item != fEntryList.end(); item++) {
// Look for a previous instance of this entry if ((*item)->ref == *ref && !strcasecmp((*item)->sig.c_str(), appSig)) {
std::list<recent_entry*>::iterator item; fEntryList.erase(item);
for (item = fEntryList.begin(); item != fEntryList.end(); item++) { break;
if ((*item)->ref == *ref && (*item)->sig == sig) {
fEntryList.erase(item);
break;
}
} }
// Add this entry to the front of the list
recent_entry *entry = new(nothrow) recent_entry(ref, appSig, 0);
error = entry ? B_OK : B_NO_MEMORY;
if (!error)
fEntryList.push_front(entry);
} }
return error;
// Add this entry to the front of the list
recent_entry *entry = new (nothrow) recent_entry(ref, appSig, 0);
if (entry == NULL)
return B_NO_MEMORY;
try {
fEntryList.push_front(entry);
} catch (...) {
return B_NO_MEMORY;
}
return B_OK;
} }
// Get
/*! \brief Returns the first \a maxCount recent apps in the \c BMessage /*! \brief Returns the first \a maxCount recent apps in the \c BMessage
pointed to by \a list. pointed to by \a list.
@@ -171,82 +154,87 @@ RecentEntries::Add(const entry_ref *ref, const char *appSig)
expected to be all lowercase. expected to be all lowercase.
*/ */
status_t status_t
RecentEntries::Get(int32 maxCount, const char *fileTypes[], int32 fileTypesCount, RecentEntries::Get(int32 maxCount, const char *fileTypes[],
const char *appSig, BMessage *result) int32 fileTypesCount, const char *appSig, BMessage *result)
{ {
status_t error = result && (fileTypesCount == 0 || (fileTypesCount > 0 && fileTypes)) if (result == NULL
? B_OK : B_BAD_VALUE; || fileTypesCount < 0
if (!error) { || (fileTypesCount > 0 && fileTypes == NULL))
result->MakeEmpty(); return B_BAD_VALUE;
std::list<recent_entry*> duplicateList; result->MakeEmpty();
std::list<recent_entry*>::iterator item;
int count = 0; std::list<recent_entry*> duplicateList;
std::list<recent_entry*>::iterator item;
for (item = fEntryList.begin(); status_t error = B_OK;
count < maxCount && item != fEntryList.end(); int count = 0;
item++)
{ for (item = fEntryList.begin();
bool match = true; error == B_OK && count < maxCount && item != fEntryList.end();
// Filter if necessary item++) {
if (fileTypesCount > 0 || appSig) { // Filter by app sig
match = false; if (appSig != NULL && strcasecmp((*item)->sig.c_str(), appSig))
// Filter by app sig continue;
if (appSig)
match = (*item)->sig == appSig; // Filter by file type
// Filter by file type if (fileTypesCount > 0) {
if (!match && fileTypesCount > 0) { char type[B_MIME_TYPE_LENGTH];
char type[B_MIME_TYPE_LENGTH]; if (GetTypeForRef(&(*item)->ref, type) == B_OK) {
if (GetTypeForRef(&(*item)->ref, type) == B_OK) { bool match = false;
for (int i = 0; i < fileTypesCount; i++) { for (int i = 0; i < fileTypesCount; i++) {
if (strcasecmp(type, fileTypes[i]) == 0) { if (!strcasecmp(type, fileTypes[i])) {
match = true; match = true;
break;
}
}
}
}
}
if (match) {
// Check for duplicates
for (std::list<recent_entry*>::iterator dupItem
= duplicateList.begin();
dupItem != duplicateList.end();
dupItem++)
{
if ((*dupItem)->ref == (*item)->ref) {
match = false;
break; break;
} }
} }
} if (!match)
if (match) { continue;
// Add the ref to the list used to check
// for duplicates, and then to the result
duplicateList.push_back(*item);
result->AddRef("refs", &(*item)->ref);
count++;
} }
} }
// Check for duplicates
bool duplicate = false;
for (std::list<recent_entry*>::iterator dupItem = duplicateList.begin();
dupItem != duplicateList.end(); dupItem++) {
if ((*dupItem)->ref == (*item)->ref) {
duplicate = true;
break;
}
}
if (duplicate)
continue;
// Add the ref to the list used to check
// for duplicates, and then to the result
try {
duplicateList.push_back(*item);
} catch (...) {
error = B_NO_MEMORY;
}
if (error == B_OK)
error = result->AddRef("refs", &(*item)->ref);
if (error == B_OK)
count++;
} }
return error; return error;
} }
// Clear
/*! \brief Clears the list of recently launched apps /*! \brief Clears the list of recently launched apps
*/ */
status_t status_t
RecentEntries::Clear() RecentEntries::Clear()
{ {
std::list<recent_entry*>::iterator i; std::list<recent_entry*>::iterator i;
for (i = fEntryList.begin(); i != fEntryList.end(); i++) for (i = fEntryList.begin(); i != fEntryList.end(); i++) {
delete *i; delete *i;
}
fEntryList.clear(); fEntryList.clear();
return B_OK; return B_OK;
} }
// Print
/*! \brief Dumps the the current list of entries to stdout. /*! \brief Dumps the the current list of entries to stdout.
*/ */
status_t status_t
@@ -254,10 +242,7 @@ RecentEntries::Print()
{ {
std::list<recent_entry*>::iterator item; std::list<recent_entry*>::iterator item;
int counter = 1; int counter = 1;
for (item = fEntryList.begin(); for (item = fEntryList.begin(); item != fEntryList.end(); item++) {
item != fEntryList.end();
item++)
{
printf("%d: device == '%ld', dir == '%lld', name == '%s', app == '%s', index == %ld\n", printf("%d: device == '%ld', dir == '%lld', name == '%s', app == '%s', index == %ld\n",
counter++, (*item)->ref.device, (*item)->ref.directory, (*item)->ref.name, counter++, (*item)->ref.device, (*item)->ref.directory, (*item)->ref.name,
(*item)->sig.c_str(), (*item)->index); (*item)->sig.c_str(), (*item)->index);
@@ -265,31 +250,31 @@ RecentEntries::Print()
return B_OK; return B_OK;
} }
// Save
status_t status_t
RecentEntries::Save(FILE* file, const char *description, const char *tag) RecentEntries::Save(FILE* file, const char *description, const char *tag)
{ {
status_t error = file ? B_OK : B_BAD_VALUE; if (file == NULL || description == NULL || tag == NULL)
if (!error) { return B_BAD_VALUE;
fprintf(file, "# %s\n", description);
/* In order to write our entries out in the format used by the fprintf(file, "# %s\n", description);
Roster settings file, we need to collect all the signatures
for each entry in one place, while at the same time updating /* In order to write our entries out in the format used by the
the index values for each entry/sig pair to reflect the current Roster settings file, we need to collect all the signatures
ordering of the list. I believe this is the data structure for each entry in one place, while at the same time updating
R5 actually maintains all the time, as their indices do not the index values for each entry/sig pair to reflect the current
change over time (whereas ours will). If our implementation ordering of the list. I believe this is the data structure
proves to be slower that R5, we may want to consider using R5 actually maintains all the time, as their indices do not
the data structure pervasively. change over time (whereas ours will). If our implementation
*/ proves to be slower that R5, we may want to consider using
std::map<entry_ref, std::list<recent_entry*> > map; the data structure pervasively.
uint32 count = fEntryList.size(); */
std::map<entry_ref, std::list<recent_entry*> > map;
uint32 count = fEntryList.size();
try {
for (std::list<recent_entry*>::iterator item = fEntryList.begin(); for (std::list<recent_entry*>::iterator item = fEntryList.begin();
item != fEntryList.end(); item != fEntryList.end(); count--, item++) {
count--, item++)
{
recent_entry *entry = *item; recent_entry *entry = *item;
if (entry) { if (entry) {
entry->index = count; entry->index = count;
@@ -300,49 +285,47 @@ RecentEntries::Save(FILE* file, const char *description, const char *tag)
fEntryList.size() - count)); fEntryList.size() - count));
} }
} }
} catch (...) {
for (std::map<entry_ref, std::list<recent_entry*> >::iterator mapItem return B_NO_MEMORY;
= map.begin();
mapItem != map.end();
mapItem++)
{
// We're going to need to properly escape the path name we
// get, which will at absolute worst double the length of
// the string.
BPath path;
char escapedPath[B_PATH_NAME_LENGTH*2];
status_t outputError = path.SetTo(&mapItem->first);
if (!outputError) {
BPrivate::Storage::escape_path(path.Path(), escapedPath);
fprintf(file, "%s %s", tag, escapedPath);
std::list<recent_entry*> &list = mapItem->second;
int32 i = 0;
for (std::list<recent_entry*>::iterator item = list.begin();
item != list.end();
i++, item++)
{
recent_entry *entry = *item;
if (entry)
fprintf(file, " \"%s\" %ld", entry->sig.c_str(), entry->index);
else {
DBG(OUT("WARNING: RecentEntries::Save(): The entry %ld entries "
"from the front of the compiled recent_entry* list for the "
"entry ref (%ld, %lld, '%s') was found to be NULL\n",
i, mapItem->first.device, mapItem->first.directory,
mapItem->first.name));
}
}
fprintf(file, "\n");
} else {
DBG(OUT("WARNING: RecentEntries::Save(): entry_ref_to_path() failed on "
"the entry_ref (%ld, %lld, '%s') with error 0x%lx\n",
mapItem->first.device, mapItem->first.directory,
mapItem->first.name, outputError));
}
}
fprintf(file, "\n");
} }
return error;
for (std::map<entry_ref, std::list<recent_entry*> >::iterator mapItem = map.begin();
mapItem != map.end(); mapItem++) {
// We're going to need to properly escape the path name we
// get, which will at absolute worst double the length of
// the string.
BPath path;
char escapedPath[B_PATH_NAME_LENGTH*2];
status_t outputError = path.SetTo(&mapItem->first);
if (!outputError) {
BPrivate::Storage::escape_path(path.Path(), escapedPath);
fprintf(file, "%s %s", tag, escapedPath);
std::list<recent_entry*> &list = mapItem->second;
int32 i = 0;
for (std::list<recent_entry*>::iterator item = list.begin();
item != list.end(); i++, item++) {
recent_entry *entry = *item;
if (entry)
fprintf(file, " \"%s\" %ld", entry->sig.c_str(), entry->index);
else {
DBG(OUT("WARNING: RecentEntries::Save(): The entry %ld entries "
"from the front of the compiled recent_entry* list for the "
"entry ref (%ld, %lld, '%s') was found to be NULL\n",
i, mapItem->first.device, mapItem->first.directory,
mapItem->first.name));
}
}
fprintf(file, "\n");
} else {
DBG(OUT("WARNING: RecentEntries::Save(): entry_ref_to_path() failed on "
"the entry_ref (%ld, %lld, '%s') with error 0x%lx\n",
mapItem->first.device, mapItem->first.directory,
mapItem->first.name, outputError));
}
}
fprintf(file, "\n");
return B_OK;
} }
@@ -355,20 +338,20 @@ RecentEntries::Save(FILE* file, const char *description, const char *tag)
status_t status_t
RecentEntries::GetTypeForRef(const entry_ref *ref, char *result) RecentEntries::GetTypeForRef(const entry_ref *ref, char *result)
{ {
if (ref == NULL || result == NULL)
return B_BAD_VALUE;
// Read the type
BNode node; BNode node;
status_t error = ref && result ? B_OK : B_BAD_VALUE; status_t error = node.SetTo(ref);
// Read the type and force to lowercase if (error == B_OK) {
if (!error)
error = node.SetTo(ref);
if (!error) {
ssize_t bytes = node.ReadAttr("BEOS:TYPE", B_MIME_STRING_TYPE, ssize_t bytes = node.ReadAttr("BEOS:TYPE", B_MIME_STRING_TYPE,
0, result, B_MIME_TYPE_LENGTH-1); 0, result, B_MIME_TYPE_LENGTH - 1);
if (bytes < 0) if (bytes < B_OK)
error = bytes; error = bytes;
else else
result[bytes] = '\0'; result[bytes] = '\0';
} }
if (!error)
BPrivate::Storage::to_lower(result);
return error; return error;
} }