Introduction
This is a simple Firefox bookmark manager. With KingMark you can import, manage and export Firefox bookmarks as a HTML or *.url or XML file. KingMark works with XML, first converts the Firefox bookmark file into the XML file and then converts it into the HTML file.
Using the Code
Creating XML file
KingMark creates an XML file with unique names for each node. For example, this is a node in the XML file:
<NODE9 NAME="FireFox" ADD_DATE="1213909970"
LAST_MODIFIED="1220234375" DESC="">
<BOOKMARK10 NAME="Mozilla - Home"
HREF="http://en-us.www.mozilla.com/en-US/"
SHORTCUTURL="mozila" DESC=""
ADD_DATE="1183006386" LAST_MODIFIED="1220234476"
ICON_URI="" ICON="" />
<BOOKMARK11 NAME="mozillaZine Forums"
HREF="http://forums.mozillazine.org/index.php"
SHORTCUTURL="" DESC="" ADD_DATE="1214351419" LAST_MODIFIED="1220233809"
ICON_URI="" ICON="" />
<BOOKMARK12 NAME="Mozilla Support"
HREF="http://support.mozilla.com/tiki-my_tiki.php#content_forum"
SHORTCUTURL="" DESC="" ADD_DATE="1214143305" LAST_MODIFIED="1220233808"
ICON_URI="" ICON="" />
<BOOKMARK13 NAME="AfzoneHaye FF"
HREF="http://addons.mozillafirefox.ir/" SHORTCUTURL=""
DESC="" ADD_DATE="1218070432" LAST_MODIFIED="1219953174"
ICON_URI="" ICON="" />
</NODE9>
As you can see, each node has a unique name so I used these names for denominating TreeView nodes' names. Well by this denomination we can find each node in an XML file and TreeView control easily.
I saved the biggest node number (for example : <BOOKMARK13 ... />) in an attribute (ELEMENTS
) in the root node. With this attribute we can find the latest number used in denomination and we start denominating after it. And with OPTIMIZE XML FILE, KingMark arranges the XML elements .
First: KingMark converts the FF BookMark file (HTML file) to the List<string>
object (intermediate code)
You can see the intermediate code with checking Trace in Settings.
When you check Trace, the private void trace(List<string> list)
method creates trace.txt
beside your FF bookmark file that includes intermediate code for generating an XML file.
After KingMark converts the List<string>
object to the XML file with the System.Xml.XmlWriter
class and the below method:
private void ListToXml(List<string> list)
{
string name = "";
string href = "";
string icon = "";
string iconUrl = "";
string desc = "";
string keyWords = "";
string addDate = "";
string lastModified = "";
try
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.Encoding = Encoding.UTF8;
settings.ConformanceLevel = ConformanceLevel.Document;
System.Xml.XmlWriter Writer;
Writer = XmlWriter.Create(temporaryFileName, settings);
Writer.WriteStartDocument();
Writer.WriteComment(XmlDescription);
Writer.WriteStartElement(rootNodeName);
Writer.WriteAttributeString("ELEMENTS", list.Count.ToString());
for (int i = 1; i < list.Count; i++)
{
if (Regex.IsMatch(list[i], @"\<HR\>"))
{
continue;
}
else if (Regex.IsMatch(list[i], @"\<NODE\>"))
{
name = Regex.Match(list[i - 1].Trim(), "NAME=\"[^\"]*\"").ToString();
name = Regex.Replace(name, "NAME|\"|=", "");
desc = Regex.Match(list[i - 1].Trim(),
"DESC=\"[^\"]*\"").ToString();
desc = Regex.Replace(desc, "DESC|\"|=", "");
addDate = Regex.Match(list[i - 1].Trim(),
"ADD_DATE=\"[^\"]*\"").ToString();
addDate = Regex.Replace(addDate, "ADD_DATE|\"|=", "");
lastModified = Regex.Match(list[i - 1].Trim(),
"LAST_MODIFIED=\"[^\"]*\"").ToString();
lastModified = Regex.Replace(lastModified,
"LAST_MODIFIED|\"|=", "");
Writer.WriteStartElement("NODE" + i.ToString());
Writer.WriteAttributeString("NAME", name);
Writer.WriteAttributeString("ADD_DATE", addDate);
Writer.WriteAttributeString("LAST_MODIFIED", lastModified);
Writer.WriteAttributeString("DESC", desc);
}
else if (list[i].Trim() == "</NODE>")
{
if (i + 1 != list.Count)
Writer.WriteEndElement();
}
else if (!Regex.IsMatch(list[i + 1], @"\<NODE\>"))
{
name = Regex.Match(list[i], "NAME=\"[^\"]*\"").ToString();
name = Regex.Replace(name, "NAME|\"|=", "");
href = Regex.Match(list[i].Trim(),
"HREF=\"[^\"]*\"").ToString();
href = Regex.Replace(href, "HREF|\"|=", "");
iconUrl = Regex.Match(list[i].Trim(),
"ICON_URI=\"[^\"]*\"").ToString();
iconUrl = Regex.Replace(iconUrl,
"ICON_URI|\"|=", "");
icon = Regex.Match(list[i].Trim(),
"ICON=\"[^\"]*\"").ToString();
icon = Regex.Replace(icon,
"\"|ICON|=", "");
desc = Regex.Match(list[i].Trim(),
"DESC=\"[^\"]*\"").ToString();
desc = Regex.Replace(desc, "DESC|\"|=", "");
keyWords = Regex.Match(list[i].Trim(),
"SHORTCUTURL=\"[^\"]*\"").ToString();
keyWords = Regex.Replace(keyWords,
"SHORTCUTURL|\"|=", "");
addDate = Regex.Match(list[i].Trim(),
"ADD_DATE=\"[^\"]*\"").ToString();
addDate = Regex.Replace(addDate, "ADD_DATE|\"|=", "");
lastModified = Regex.Match(list[i].Trim(),
"LAST_MODIFIED=\"[^\"]*\"").ToString();
lastModified = Regex.Replace(lastModified,
"LAST_MODIFIED|\"|=", "");
Writer.WriteStartElement("BOOKMARK" + i.ToString());
Writer.WriteAttributeString("NAME", name.Trim());
Writer.WriteAttributeString("HREF", href.Trim());
Writer.WriteAttributeString("SHORTCUTURL", keyWords.Trim());
Writer.WriteAttributeString("DESC", desc.Trim());
Writer.WriteAttributeString("ADD_DATE", addDate.Trim());
Writer.WriteAttributeString("LAST_MODIFIED", lastModified.Trim());
Writer.WriteAttributeString("ICON_URI", iconUrl.Trim());
Writer.WriteAttributeString("ICON", icon.Trim());
Writer.WriteEndElement();
}
}
Writer.WriteEndDocument();
Writer.Flush();
Writer.Close();
X_Element = XElement.Load(temporaryFileName);
}
catch (Exception ex)
{
StackFrame file_info = new StackFrame(true);
error(ref file_info, ex.Message);
}
}
XML File to TreeView
After creating the XML file, an XML file should be loaded in the TreeView control. (see below methods) If you check Load Icons in settings each icon of nodes will show.
private void XmlToTree()
{
optimize_menuItem.Enabled = exportIE_favorites.Enabled =
exportXML_menuItem.Enabled =
exportHtml_menuItem.Enabled = true;
this.treeViewBookMark.Enabled = true;
this.XElementClopboard = null;
this.TreeNodeClipboard = null;
try
{
XmlDocument dom = new XmlDocument();
dom.Load(this.temporaryFileName);
treeViewBookMark.Nodes.Clear();
treeViewBookMark.Nodes.Add(new TreeNode(dom.DocumentElement.Name));
TreeNode tNode = new TreeNode(rootNodeName);
tNode = treeViewBookMark.Nodes[0];
tNode.Name = rootNodeName;
AddNode(dom.DocumentElement, tNode);
treeViewBookMark.SelectedNode = treeViewBookMark.Nodes[0];
selected_node = treeViewBookMark.Nodes[0];
treeViewBookMark.SelectedNode.Expand();
}
catch (Exception ex)
{
textBoxIconURL.Enabled = textBoxDesc.Enabled = textBoxName.Enabled
= buttonDelIcon.Enabled = textBoxKeyWords.Enabled
= textBoxHref.Enabled = false;
optimize_menuItem.Enabled = exportIE_favorites.Enabled
= exportXML_menuItem.Enabled = exportHtml_menuItem.Enabled
= false;
this.treeViewBookMark.Enabled = false;
StackFrame file_info = new StackFrame(true);
error(ref file_info, ex.Message);
return;
}
}
private void AddNode(XmlNode inXmlNode, TreeNode inTreeNode)
{
try
{
XmlNode xNode;
TreeNode tNode;
XmlNodeList nodeList;
int i;
int j = -1;
if (inXmlNode.HasChildNodes)
{
nodeList = inXmlNode.ChildNodes;
for (i = 0; i <= nodeList.Count - 1; i++)
{
if (inXmlNode.ChildNodes[i].Name.Equals("HR"))
continue;
j++;
xNode = inXmlNode.ChildNodes[i];
TreeNode newTreeNode;
newTreeNode = new TreeNode(xNode.Attributes["NAME"].Value);
newTreeNode.Name = xNode.Name;
if (loadIcons_menuItem.Checked)
{
Image icon = createIcon(xNode.Name);
if (Regex.IsMatch(inXmlNode.ChildNodes[i].Name, "NODE"))
{
newTreeNode.ImageIndex = 0;
newTreeNode.SelectedImageIndex = 0;
}
else if (icon != null && Regex.IsMatch(inXmlNode.ChildNodes[i].Name,
"BOOKMARK"))
{
imageList1.Images.Add(icon);
newTreeNode.ImageIndex = imageList1.Images.Count - 1;
newTreeNode.SelectedImageIndex = imageList1.Images.Count - 1;
}
else
{
newTreeNode.ImageIndex = 1;
newTreeNode.SelectedImageIndex = 1;
}
}
else
{
if (Regex.IsMatch(inXmlNode.ChildNodes[i].Name, "NODE"))
{
newTreeNode.ImageIndex = 0;
newTreeNode.SelectedImageIndex = 0;
}
else if (Regex.IsMatch(inXmlNode.ChildNodes[i].Name, "BOOKMARK"))
{
newTreeNode.ImageIndex = 1;
newTreeNode.SelectedImageIndex = 1;
}
}
inTreeNode.Nodes.Add(newTreeNode);
tNode = inTreeNode.Nodes[j];
AddNode(xNode, tNode);
}
}
else
{
inTreeNode.Text = (inXmlNode.Attributes["NAME"].Value).Trim();
}
}
catch (Exception ex)
{
textBoxIconURL.Enabled = textBoxDesc.Enabled =
textBoxName.Enabled = buttonDelIcon.Enabled =
textBoxKeyWords.Enabled = textBoxHref.Enabled =
false;
optimize_menuItem.Enabled = exportIE_favorites.Enabled =
exportXML_menuItem.Enabled =
exportHtml_menuItem.Enabled = false;
treeViewBookMark.Nodes.Clear();
this.treeViewBookMark.Enabled = false;
StackFrame file_info = new StackFrame(true);
error(ref file_info, ex.Message);
return;
}
}
KingMark Features
TreeView Drag-n-Drop
You can export IE favorite files directly, using the Drag a TreeView folder or file out to the Window.
Unlike the above, you can import IE favorite files to KingMark with drag it into the TreeView.
Also, you can import IE6 (I had IE6, maybe on IE7 or IE8 doesn't work) website addresses and FF3 (I had FF3, maybe on FF2 or FF1 doesn't work) website tabs into KingMark with dragging it in its TreeView Control.
Exporting Bookmarks for Internet Explorer or Firefox Browser
With KingMark you can export all or part of bookmarks for FF(HTML file) or IE(*.url file)
For exporting all bookmarks use the Export Menu:
For exporting some bookmarks use TreeView's contextMenuStrip
:
Export for FF
Export for IE
Quick Search
I used LINQ to search the XML file (see below method)
private void textBoxSearchTxt_TextChanged(object sender, EventArgs e)
{
string searchTxt = Regex.Replace(textBoxSearchTxt.Text.Trim(),
@"[\$\^\{\[\(\|\)\*\+\?\\]", "");
if (searchTxt == "")
{
this.listView1.Items.Clear();
return;
}
try
{
var searchNodes = from nodes in X_Element.Descendants()
where
(nodes.Attribute("NAME") != null
Regex.IsMatch(nodes.Attribute("NAME").Value,
searchTxt, RegexOptions.IgnoreCase))
|| (nodes.Attribute("HREF") != null
Regex.IsMatch(nodes.Attribute("HREF").Value, searchTxt,
RegexOptions.IgnoreCase))
|| (nodes.Attribute("SHORTCUTURL") != null
Regex.IsMatch(nodes.Attribute("SHORTCUTURL").Value,
searchTxt,
RegexOptions.IgnoreCase))
select nodes;
listView1.Items.Clear();
foreach (var node in searchNodes)
{
try
{
ListViewItem item = new ListViewItem(new string[]
{ node.Attribute("NAME").Value, node.Attribute("HREF").Value });
item.Name = node.Name.ToString();
listView1.Items.Add(item);
}
catch
{
continue;
}
}
}
catch { }
}
Generating Website Preview Image
You can find WebsiteThumbnailImage.cs
in my project and figure out how I did it.
Notify Icon
When you minimize the KingMark window, KingMark creates a contextMenuStrip
with the TreeView nodes and show a notifyIcon
here:
And you can access to your bookmarks easily:
How can we convert TreeView to contextMenuStrip
:
I wrote these methods to do that, and these method did it well. But if you have a better way I thank you if you say it to me.
void createContextMenuStripNotifyIcon()
{
try
{
if (this.treeViewBookMark.Nodes.Count <= 0) return;
contextMenuStripNotifyIcon.Items.Clear();
foreach (TreeNode node in this.treeViewBookMark.Nodes[0].Nodes)
{
ToolStripMenuItem toolStripMenuItem = new ToolStripMenuItem();
if (node.GetNodeCount(true) > 0)
{
toolStripMenuItem.BackColor = contextMenuStripNotifyIcon.BackColor;
toolStripMenuItem.Image = imageList1.Images[node.ImageIndex];
toolStripMenuItem.Text = node.Text.Length > 30 ?
node.Text.Substring(0, 30) + " ..." : node.Text;
toolStripMenuItem.Name = node.Name;
createContextMenuStripNotifyIcon(node, ref toolStripMenuItem);
contextMenuStripNotifyIcon.Items.Add(toolStripMenuItem);
}
else
{
toolStripMenuItem.BackColor = contextMenuStripNotifyIcon.BackColor;
toolStripMenuItem.Image = imageList1.Images[node.ImageIndex];
toolStripMenuItem.Text = node.Text.Length > 30 ?
node.Text.Substring(0, 30) + " ..." : node.Text;
toolStripMenuItem.Name = node.Name;
toolStripMenuItem.MouseDown +=
new MouseEventHandler(contextMenuStripNotifyIconItems_MouseDown);
contextMenuStripNotifyIcon.Items.Add(toolStripMenuItem);
}
}
}
catch (Exception ex)
{
StackFrame file_info = new StackFrame(true);
error(ref file_info, ex.Message);
}
}
void createContextMenuStripNotifyIcon(TreeNode nodes,
ref ToolStripMenuItem toolStripMenuItem)
{
foreach (TreeNode node in nodes.Nodes)
{
if (node.GetNodeCount(true) > 0)
{
ToolStripMenuItem newToolStripMenuItem = new ToolStripMenuItem();
newToolStripMenuItem.BackgroundImage = imageList1.Images[node.ImageIndex];
newToolStripMenuItem.BackgroundImageLayout = ImageLayout.None;
newToolStripMenuItem.Text = node.Text.Length > 30 ?
node.Text.Substring(0, 30) + " ..." : node.Text;
newToolStripMenuItem.Name = node.Name;
createContextMenuStripNotifyIcon(node, ref newToolStripMenuItem);
toolStripMenuItem.DropDown.Items.Add(newToolStripMenuItem);
}
else
{
ToolStripMenuItem newToolStripMenuItem = new ToolStripMenuItem();
newToolStripMenuItem.BackgroundImage = imageList1.Images[node.ImageIndex];
newToolStripMenuItem.BackgroundImageLayout = ImageLayout.None;
newToolStripMenuItem.Text = node.Text.Length > 30 ?
node.Text.Substring(0, 30) + " ..." : node.Text;
newToolStripMenuItem.Name = node.Name;
newToolStripMenuItem.MouseDown +=
new MouseEventHandler(contextMenuStripNotifyIconItems_MouseDown);
toolStripMenuItem.DropDown.Items.Add(newToolStripMenuItem);
}
}
}
void contextMenuStripNotifyIconItems_MouseDown(object sender, MouseEventArgs e)
{
try
{
if (e.Button == MouseButtons.Left)
Process.Start(GetHref(((ToolStripMenuItem)sender).Name));
}
catch
{
StackFrame file_info = new StackFrame(true);
error(ref file_info, "Invalid URL");
}
}