mirror of https://github.com/roytam1/kmeleon.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
485 lines
13 KiB
485 lines
13 KiB
/* |
|
* Copyright (C) 2000 Brian Harris, Mark Liffiton |
|
* |
|
* This program is free software; you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License as published by |
|
* the Free Software Foundation; either version 2, or (at your option) |
|
* any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with this program; if not, write to the Free Software |
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|
*/ |
|
|
|
#ifndef BOOKMARK_NODE_H |
|
#define BOOKMARK_NODE_H |
|
|
|
#include <time.h> |
|
#include <string> |
|
#include <windows.h> |
|
|
|
const int BOOKMARK_BOOKMARK = 0; // this node is a real bookmark, all fields valid |
|
const int BOOKMARK_FOLDER = 1; // "children" is not empty. url is not used |
|
const int BOOKMARK_SEPARATOR= 2; // this node is a separator, url, title, and children are not used |
|
|
|
const int BOOKMARK_FLAG_TB = 0x1; // Toolbar Folder |
|
const int BOOKMARK_FLAG_NB = 0x2; // New Bookmarks Folder |
|
const int BOOKMARK_FLAG_BM = 0x4; // Bookmark Menu Folder |
|
const int BOOKMARK_FLAG_GRP = 0x8; // Bookmark Group Folder |
|
|
|
typedef int cmp_t(const char *, const char *, unsigned int); |
|
void quicksort(char *a, size_t n, size_t es, cmp_t *cmp, unsigned int flag); |
|
static int compareBookmarks(const char *e1, const char *e2, unsigned int sortorder); |
|
char *stristr(const char *String, const char *Pattern); |
|
|
|
class CBookmarkNode { |
|
public: |
|
int id; |
|
std::string text; |
|
std::string url; |
|
std::string nick; |
|
std::string desc; |
|
std::string charset; |
|
std::string m_id; |
|
std::string feedurl; |
|
std::string icon; |
|
std::string iconurl; |
|
int type; |
|
int flags; |
|
time_t addDate; |
|
time_t lastVisit; |
|
time_t lastModified; |
|
CBookmarkNode *next; |
|
CBookmarkNode *child; |
|
CBookmarkNode *lastChild; |
|
|
|
inline CBookmarkNode() |
|
{ |
|
id = 0; |
|
text = ""; |
|
url = ""; |
|
nick = ""; |
|
desc = ""; |
|
charset = ""; |
|
type = 0; |
|
flags = 0; |
|
next = NULL; |
|
child = NULL; |
|
lastChild = NULL; |
|
|
|
addDate = 0; |
|
lastVisit = 0; |
|
lastModified = 0; |
|
} |
|
inline CBookmarkNode(int id, const char *text, const char *url, const char *nick, const char *desc, const char *charset, int type, time_t addDate=0, time_t lastVisit=0, time_t lastModified=0, const char* m_id="", const char* feedurl="", const char* icon = "", const char* iconurl = "") |
|
{ |
|
this->id = id; |
|
this->text = text; |
|
this->url = url; |
|
this->nick = nick ? nick : ""; |
|
this->desc = desc ? desc : ""; |
|
this->charset = charset ? charset : ""; |
|
this->m_id = m_id ? m_id : ""; |
|
this->feedurl = feedurl ? feedurl : ""; |
|
this->icon = icon ? icon: ""; |
|
this->iconurl = iconurl ? iconurl : ""; |
|
this->type = type; |
|
this->flags = 0; |
|
this->next = NULL; |
|
this->child = NULL; |
|
this->lastChild = NULL; |
|
this->addDate = addDate; |
|
this->lastVisit = lastVisit; |
|
this->lastModified = lastModified; |
|
} |
|
inline CBookmarkNode(int id, std::string &text, std::string &url, std::string &nick, std::string &desc, std::string &charset, int type, time_t addDate=0, time_t lastVisit=0, time_t lastModified=0, std::string m_id ="", std::string feedurl="", std::string icon="", std::string iconurl="") |
|
{ |
|
this->id = id; |
|
this->text = text; |
|
this->url = url; |
|
this->nick = nick; |
|
this->desc = desc; |
|
this->charset = charset; |
|
this->m_id = m_id; |
|
this->feedurl = feedurl; |
|
this->icon = icon; |
|
this->iconurl = iconurl; |
|
this->type = type; |
|
this->flags = 0; |
|
this->next = NULL; |
|
this->child = NULL; |
|
this->lastChild = NULL; |
|
this->addDate = addDate; |
|
this->lastVisit = lastVisit; |
|
this->lastModified = lastModified; |
|
} |
|
inline ~CBookmarkNode() |
|
{ |
|
// when we delete next, it's destructor will delete it's next, which will delete it's next, etc... |
|
if (next) |
|
delete next; |
|
|
|
// same with child... |
|
if (child) |
|
delete child; |
|
} |
|
inline CBookmarkNode &operator=(CBookmarkNode &n2) |
|
{ |
|
id = n2.id; |
|
text = n2.text; |
|
url = n2.url; |
|
nick = n2.nick; |
|
desc = n2.desc; |
|
charset = n2.charset; |
|
m_id = n2.m_id; |
|
feedurl = n2.feedurl; |
|
icon = n2.icon; |
|
iconurl = n2.iconurl; |
|
type = n2.type; |
|
flags = n2.flags; |
|
addDate = n2.addDate; |
|
lastVisit = n2.lastVisit; |
|
lastModified = n2.lastModified; |
|
|
|
if (child) { |
|
delete child; |
|
} |
|
if (next) { |
|
delete next; |
|
} |
|
|
|
if (n2.child) { |
|
child = new CBookmarkNode(); |
|
(*child) = (*n2.child); |
|
|
|
// need to rebuild pointer to lastChild - can't just grab it from n2 |
|
lastChild = child; |
|
while (lastChild->next) lastChild = lastChild->next; |
|
} |
|
else { |
|
child = NULL; |
|
} |
|
|
|
if (n2.next) { |
|
next = new CBookmarkNode(); |
|
(*next) = (*n2.next); |
|
} |
|
else { |
|
next = NULL; |
|
} |
|
|
|
return *this; |
|
} |
|
inline void AddChild(CBookmarkNode *newChild) |
|
{ |
|
if (child) { |
|
lastChild->next = newChild; |
|
} |
|
else { |
|
child = newChild; |
|
} |
|
lastChild = newChild; |
|
} |
|
BOOL UnlinkNode(CBookmarkNode *node) |
|
{ |
|
CBookmarkNode *c; |
|
CBookmarkNode *previous = NULL; |
|
|
|
for (c=child; c; previous=c, c=c->next) { |
|
if (c == node) { |
|
// found our node to delete! |
|
|
|
// first redirect traffic around it |
|
if (previous) { |
|
previous->next = node->next; |
|
} |
|
else { |
|
child = node->next; |
|
} |
|
|
|
// if we are the last item, set our parent's lastChild to the item before us |
|
if (!node->next) { |
|
lastChild = previous; |
|
} |
|
|
|
// WE HAVE TO SET OUR NEXT TO NULL |
|
// if we don't do this, when we are deleted, we will try to delete our next, which would result |
|
// in pretty much the whole menu being deleted |
|
node->next = NULL; |
|
|
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
BOOL DeleteNode(CBookmarkNode *node) |
|
{ |
|
if (UnlinkNode(node)) { |
|
delete node; |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
CBookmarkNode *FindFolder(HMENU id) |
|
{ |
|
CBookmarkNode *c; |
|
for (c=child; c; c=c->next) { |
|
if (c->type == BOOKMARK_FOLDER) { |
|
if (c->id == (int)id) |
|
return c; |
|
CBookmarkNode *retNode = c->FindFolder(id); |
|
if (retNode) return retNode; |
|
} |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
CBookmarkNode *FindNode(int id) |
|
{ |
|
CBookmarkNode *c; |
|
for (c=child; c; c=c->next) { |
|
if (c->type == BOOKMARK_SEPARATOR) { |
|
continue; |
|
} |
|
else if (c->type == BOOKMARK_FOLDER) { |
|
// FIXME - they currently could be stored out of order after being shuffled around in the edit dialog |
|
// so we can't use this optimization. |
|
// - Perhaps re-ID bookmarks after edit? It might be worth it, if speed becomes an issue. |
|
/* |
|
// this little bit of code is for optimizations |
|
// it assumes the items are stored in order. |
|
// if the items ever get out of order, we need to remove this code |
|
CBookmarkNode *lc = c->lastChild; |
|
if (lc && lc->type == BOOKMARK_BOOKMARK && lc->id < id) { |
|
continue; |
|
} |
|
*/ |
|
CBookmarkNode *retNode = c->FindNode(id); |
|
|
|
if (retNode) { |
|
// found it in a sub-node |
|
return retNode; |
|
} |
|
} |
|
else if (c->id == id) { |
|
// this is it! |
|
return c; |
|
} |
|
} |
|
// // We couldn't find it. Rather than returning null and risking a null pointer crash, return ourself |
|
// return this; |
|
// Scratch that. We return NULL and just fix anything that crashes. |
|
return NULL; |
|
} |
|
CBookmarkNode *FindUrl(const char *url) |
|
{ |
|
CBookmarkNode *c; |
|
for (c=child; c; c=c->next) { |
|
if (c->type == BOOKMARK_SEPARATOR) { |
|
continue; |
|
} |
|
if (c->type == BOOKMARK_FOLDER) { |
|
CBookmarkNode *retNode = c->FindUrl(url); |
|
if (retNode) { |
|
// found it in a sub-node |
|
return retNode; |
|
} |
|
} |
|
else if (strcmp((char*)c->url.c_str(), url) == 0) { |
|
// this is it! |
|
return c; |
|
} |
|
} |
|
return NULL; |
|
} |
|
CBookmarkNode *FindNick(const char *nick) |
|
{ |
|
CBookmarkNode *c; |
|
for (c=child; c; c=c->next) { |
|
if (c->type == BOOKMARK_SEPARATOR) { |
|
continue; |
|
} |
|
else if (c->type == BOOKMARK_FOLDER) { |
|
if (strcmp((char*)c->nick.c_str(), nick) == 0) { |
|
// this is it! |
|
return c; |
|
} |
|
|
|
CBookmarkNode *retNode = c->FindNick(nick); |
|
|
|
if (retNode) { |
|
// found it in a sub-node |
|
return retNode; |
|
} |
|
} |
|
else if (strcmp((char*)c->nick.c_str(), nick) == 0) { |
|
// this is it! |
|
return c; |
|
} |
|
} |
|
return NULL; |
|
} |
|
CBookmarkNode *FindSpecialNode(int flag) |
|
{ |
|
CBookmarkNode *c; |
|
for (c=child; c; c=c->next) { |
|
if (c->flags & flag) { |
|
// this is it! |
|
return c; |
|
} |
|
else if (c->type == BOOKMARK_FOLDER) { |
|
CBookmarkNode *retNode = c->FindSpecialNode(flag); |
|
|
|
if (retNode != c) { |
|
// found it in a sub-node |
|
return retNode; |
|
} |
|
} |
|
} |
|
// We couldn't find it. Rather than returning null and risking a null pointer crash, return ourself |
|
return this; |
|
} |
|
int Index(int &mypos, CBookmarkNode *node) |
|
{ |
|
CBookmarkNode *c; |
|
for (c=child; c; c=c->next) { |
|
mypos++; |
|
if (c->type == BOOKMARK_SEPARATOR) |
|
continue; |
|
else if (node == c) |
|
return mypos; |
|
|
|
if (c->type == BOOKMARK_FOLDER) { |
|
int newpos = c->Index(mypos, node); |
|
if (newpos >= 0) |
|
return newpos; |
|
} |
|
} |
|
return -1; |
|
} |
|
int Search(const char *str, int pos, int &mypos, int &firstpos, CBookmarkNode **node) |
|
{ |
|
CBookmarkNode *c; |
|
for (c=child; c; c=c->next) { |
|
mypos++; |
|
if (c->type == BOOKMARK_SEPARATOR) { |
|
continue; |
|
} |
|
else if (stristr(c->text.c_str(), str) || |
|
stristr(c->url.c_str(), str) || |
|
stristr(c->nick.c_str(), str) || |
|
stristr(c->desc.c_str(), str)) { |
|
if (mypos >= pos) { |
|
// this is it! |
|
if (node) |
|
*node = c; |
|
return mypos; |
|
} |
|
else if (firstpos == -1) { |
|
firstpos = mypos; |
|
} |
|
} |
|
|
|
if (c->type == BOOKMARK_FOLDER) { |
|
|
|
int newpos = c->Search(str, pos, mypos, firstpos, node); |
|
|
|
if (newpos >= pos) { |
|
// found it in a sub-node |
|
return newpos; |
|
} |
|
} |
|
} |
|
return firstpos; |
|
} |
|
void sort(int sortorder) |
|
{ |
|
if (!child) |
|
return; |
|
|
|
CBookmarkNode *c; |
|
int i = 0; |
|
for (c=child; c; c=c->next) |
|
i++; |
|
if (i == 0) |
|
return; |
|
void **buf = (void**)calloc(i, sizeof(void*)); |
|
if (!buf) |
|
return; |
|
for (i=0,c=child; c; c=c->next,i++) { |
|
buf[i] = (void*)c; |
|
} |
|
quicksort((char*)buf, i, sizeof(void*), &compareBookmarks, sortorder); |
|
child = ((CBookmarkNode*)buf[0]); |
|
for (int j=0; j<i-1; j++) { |
|
c = ((CBookmarkNode*)buf[j]); |
|
c->next = ((CBookmarkNode*)buf[j+1]); |
|
} |
|
c = ((CBookmarkNode*)buf[i-1]); |
|
c->next = NULL; |
|
lastChild = c; |
|
free(buf); |
|
for (c=child; c; c=c->next) { |
|
if (c->type == BOOKMARK_FOLDER && (sortorder & 1)) { |
|
c->sort(sortorder); |
|
} |
|
} |
|
} |
|
}; |
|
|
|
static int compareBookmarks(const char *e1, const char *e2, unsigned int sortorder) |
|
{ |
|
#define SORT_BITS 3 |
|
int cmp = 0; |
|
|
|
if (e1 == e2) return 0; |
|
if (!e1) return -1; |
|
if (!e2) return 1; |
|
|
|
int recurse = (sortorder & 1); |
|
int order = ((sortorder>>1) & ((1<<SORT_BITS)-1)); |
|
int neworder = ((sortorder >> (SORT_BITS+1)) << 1) | recurse; |
|
|
|
CBookmarkNode *c1 = (CBookmarkNode *)*((void**)e1); |
|
CBookmarkNode *c2 = (CBookmarkNode *)*((void**)e2); |
|
|
|
switch (order) { |
|
case 1: |
|
cmp = c1->type - c2->type; |
|
break; |
|
case 2: |
|
cmp = lstrcmpiA((char*)c1->text.c_str(), (char*)c2->text.c_str()); |
|
break; |
|
case 3: |
|
cmp = lstrcmpiA((char*)c1->url.c_str(), (char*)c2->url.c_str()); |
|
break; |
|
case 4: |
|
cmp = c2->id - c1->id; |
|
return cmp ? cmp : -1; |
|
case 5: |
|
cmp = c2->type - c1->type; |
|
break; |
|
case 6: |
|
cmp = lstrcmpiA((char*)c2->text.c_str(), (char*)c1->text.c_str()); |
|
break; |
|
case 7: |
|
cmp = lstrcmpiA((char*)c2->url.c_str(), (char*)c1->url.c_str()); |
|
break; |
|
default: |
|
cmp = c1->id - c2->id; |
|
return cmp ? cmp : -1; |
|
break; |
|
} |
|
if (cmp == 0) |
|
return compareBookmarks(e1, e2, neworder); |
|
return cmp; |
|
} |
|
|
|
#endif
|
|
|