summaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorJens-Heiner Rechtien <hr@openoffice.org>2003-09-29 13:55:13 +0000
committerJens-Heiner Rechtien <hr@openoffice.org>2003-09-29 13:55:13 +0000
commit179f7b1630c4ce14035767c3af8055654541123c (patch)
treec188db9dd13f60ffd49e8e29ca8dfbbaaf94a458 /shell
parentd6293645ab6680afc2d810d748214770838da2d6 (diff)
INTEGRATION: CWS geordi2q06 (1.1.4); FILE ADDED
2003/09/24 11:28:43 rt 1.1.4.1: #111934#: join CWS recentdocs
Diffstat (limited to 'shell')
-rw-r--r--shell/source/unix/sysshell/recently_used_file_handler.cxx562
-rwxr-xr-xshell/source/unix/sysshell/recfile.map6
2 files changed, 568 insertions, 0 deletions
diff --git a/shell/source/unix/sysshell/recently_used_file_handler.cxx b/shell/source/unix/sysshell/recently_used_file_handler.cxx
new file mode 100644
index 000000000000..8276c201313b
--- /dev/null
+++ b/shell/source/unix/sysshell/recently_used_file_handler.cxx
@@ -0,0 +1,562 @@
+/*************************************************************************
+ *
+ * $RCSfile: recently_used_file_handler.cxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: hr $ $Date: 2003-09-29 14:55:04 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#ifndef _SYSTEMSHELL_HXX_
+#include "systemshell.hxx"
+#endif
+
+#ifndef _OSL_PROCESS_H_
+#include "osl/process.h"
+#endif
+
+#ifndef _RTL_USTRING_HXX_
+#include "rtl/ustring.hxx"
+#endif
+
+#ifndef _RTL_STRING_HXX_
+#include "rtl/string.hxx"
+#endif
+
+#include "osl/thread.h"
+
+#ifndef INCLUDED_RECENTLY_USED_FILE_HXX
+#include "recently_used_file.hxx"
+#endif
+
+#include "internal/xml_parser.hxx"
+#include "internal/i_xml_parser_event_handler.hxx"
+
+#include <map>
+#include <vector>
+#include <algorithm>
+#include <functional>
+
+namespace /* private */ {
+
+ const rtl::OUString ENVV_UPDATE_RECENTLY_USED =
+ rtl::OUString::createFromAscii("ENABLE_UPDATE_RECENTLY_USED");
+
+ //########################################
+ inline rtl::OString get_file_extension(const rtl::OString& file_url)
+ {
+ sal_Int32 index = file_url.lastIndexOf('.');
+ OSL_ENSURE((index != -1) && ((index + 1) < file_url.getLength()), "Invalid file url");
+ return file_url.copy(index + 1);
+ }
+
+ //########################################
+ typedef std::vector<string_t> string_container_t;
+
+ #define TAG_RECENT_FILES "RecentFiles"
+ #define TAG_RECENT_ITEM "RecentItem"
+ #define TAG_URI "URI"
+ #define TAG_MIME_TYPE "Mime-Type"
+ #define TAG_TIMESTAMP "Timestamp"
+ #define TAG_PRIVATE "Private"
+ #define TAG_GROUPS "Groups"
+ #define TAG_GROUP "Group"
+
+ //------------------------------------------------
+ // compare two string_t's case insensitive, may also be done
+ // by specifying special traits for the string type but in this
+ // case it's easier to do it this way
+ struct str_icase_cmp :
+ public std::binary_function<string_t, string_t, bool>
+ {
+ bool operator() (const string_t& s1, const string_t& s2) const
+ { return (0 == strcasecmp(s1.c_str(), s2.c_str())); }
+ };
+
+ //------------------------------------------------
+ struct recently_used_item
+ {
+ recently_used_item() :
+ is_private_(false)
+ {}
+
+ recently_used_item(
+ const string_t& uri,
+ const string_t& mime_type,
+ const string_container_t& groups,
+ bool is_private = false) :
+ uri_(uri),
+ mime_type_(mime_type),
+ is_private_(is_private),
+ groups_(groups)
+ {
+ timestamp_ = time(NULL);
+ }
+
+ void set_uri(const string_t& character)
+ { uri_ = character; }
+
+ void set_mime_type(const string_t& character)
+ { mime_type_ = character; }
+
+ void set_timestamp(const string_t& character)
+ {
+ time_t t;
+ if (sscanf(character.c_str(), "%ld", &t) != 1)
+ timestamp_ = -1;
+ else
+ timestamp_ = t;
+ }
+
+ void set_is_private(const string_t& character)
+ { is_private_ = true; }
+
+ void set_groups(const string_t& character)
+ { groups_.push_back(character); }
+
+ void set_nothing(const string_t& character)
+ {}
+
+ bool has_groups() const
+ {
+ return !groups_.empty();
+ }
+
+ bool has_group(const string_t& name) const
+ {
+ string_container_t::const_iterator iter_end = groups_.end();
+ return (has_groups() &&
+ iter_end != std::find_if(
+ groups_.begin(), iter_end,
+ std::bind2nd(str_icase_cmp(), name)));
+ }
+
+ void write_xml(const recently_used_file& file) const
+ {
+ write_xml_start_tag(TAG_RECENT_ITEM, file, true);
+ write_xml_tag(TAG_URI, uri_, file);
+ write_xml_tag(TAG_MIME_TYPE, mime_type_, file);
+
+ rtl::OString ts = rtl::OString::valueOf(timestamp_);
+ write_xml_tag(TAG_TIMESTAMP, ts.getStr(), file);
+
+ if (is_private_)
+ write_xml_tag(TAG_PRIVATE, file);
+
+ if (has_groups())
+ {
+ write_xml_start_tag(TAG_GROUPS, file, true);
+
+ string_container_t::const_iterator iter = groups_.begin();
+ string_container_t::const_iterator iter_end = groups_.end();
+
+ for (/**/; iter != iter_end; ++iter)
+ write_xml_tag(TAG_GROUP, (*iter), file);
+
+ write_xml_end_tag(TAG_GROUPS, file);
+ }
+ write_xml_end_tag(TAG_RECENT_ITEM, file);
+ }
+
+ void write_xml_tag(const string_t& name, const string_t& value, const recently_used_file& file) const
+ {
+ write_xml_start_tag(name, file);
+ file.write(value.c_str(), value.length());
+ write_xml_end_tag(name, file);
+ }
+
+ void write_xml_tag(const string_t& name, const recently_used_file& file) const
+ {
+ file.write("<", 1);
+ file.write(name.c_str(), name.length());
+ file.write("/>\n", 3);
+ }
+
+ void write_xml_start_tag(const string_t& name, const recently_used_file& file, bool linefeed = false) const
+ {
+ file.write("<", 1);
+ file.write(name.c_str(), name.length());
+ if (linefeed)
+ file.write(">\n", 2);
+ else
+ file.write(">", 1);
+ }
+
+ void write_xml_end_tag(const string_t& name, const recently_used_file& file) const
+ {
+ file.write("</", 2);
+ file.write(name.c_str(), name.length());
+ file.write(">\n", 2);
+ }
+
+ string_t uri_;
+ string_t mime_type_;
+ time_t timestamp_;
+ bool is_private_;
+ string_container_t groups_;
+ };
+
+ typedef std::vector<recently_used_item*> recently_used_item_list_t;
+ typedef void (recently_used_item::* SET_COMMAND)(const string_t&);
+
+ //########################################
+ // thrown if we encounter xml tags that we do not know
+ class unknown_xml_format_exception {};
+
+ //########################################
+ class recently_used_file_filter : public i_xml_parser_event_handler
+ {
+ public:
+ recently_used_file_filter(recently_used_item_list_t& item_list) :
+ item_(NULL),
+ item_list_(item_list)
+ {
+ named_command_map_[TAG_RECENT_FILES] = &recently_used_item::set_nothing;
+ named_command_map_[TAG_RECENT_ITEM] = &recently_used_item::set_nothing;
+ named_command_map_[TAG_URI] = &recently_used_item::set_uri;
+ named_command_map_[TAG_MIME_TYPE] = &recently_used_item::set_mime_type;
+ named_command_map_[TAG_TIMESTAMP] = &recently_used_item::set_timestamp;
+ named_command_map_[TAG_PRIVATE] = &recently_used_item::set_is_private;
+ named_command_map_[TAG_GROUPS] = &recently_used_item::set_nothing;
+ named_command_map_[TAG_GROUP] = &recently_used_item::set_groups;
+ }
+
+ virtual void start_element(
+ const string_t& raw_name,
+ const string_t& local_name,
+ const xml_tag_attribute_container_t& attributes)
+ {
+ if ((local_name == TAG_RECENT_ITEM) && (NULL == item_))
+ item_ = new recently_used_item;
+ }
+
+ virtual void end_element(const string_t& raw_name, const string_t& local_name)
+ {
+ if (named_command_map_.find(local_name) != named_command_map_.end())
+ (item_->*named_command_map_[local_name])(current_element_);
+ else
+ {
+ delete item_;
+ throw unknown_xml_format_exception();
+ }
+
+ if (local_name == TAG_RECENT_ITEM)
+ {
+ item_list_.push_back(item_);
+ item_ = NULL;
+ }
+ current_element_.clear();
+ }
+
+ virtual void characters(const string_t& character)
+ {
+ if (character != "\n")
+ current_element_ += character;
+ }
+
+ virtual void start_document() {}
+ virtual void end_document() {}
+
+ virtual void ignore_whitespace(const string_t& whitespaces)
+ {}
+
+ virtual void processing_instruction(
+ const string_t& target, const string_t& data)
+ {}
+
+ virtual void comment(const string_t& comment)
+ {}
+ private:
+ recently_used_item* item_;
+ std::map<string_t, SET_COMMAND> named_command_map_;
+ string_t current_element_;
+ recently_used_item_list_t& item_list_;
+ private:
+ recently_used_file_filter(const recently_used_file_filter&);
+ recently_used_file_filter& operator=(const recently_used_file_filter&);
+ };
+
+ //------------------------------------------------
+ void read_recently_used_items(
+ recently_used_file& file,
+ recently_used_item_list_t& item_list)
+ {
+ xml_parser xparser;
+ recently_used_file_filter ruff(item_list);
+
+ xparser.set_document_handler(&ruff);
+
+ char buff[16384];
+ while (!file.eof())
+ {
+ if (size_t length = file.read(buff, sizeof(buff)))
+ xparser.parse(buff, length, file.eof());
+ }
+ }
+
+ //------------------------------------------------
+ // The file ~/.recently_used shall not contain more than 500
+ // entries (see www.freedesktop.org)
+ const int MAX_RECENTLY_USED_ITEMS = 500;
+
+ class recent_item_writer
+ {
+ public:
+ recent_item_writer(
+ recently_used_file& file,
+ int max_items_to_write = MAX_RECENTLY_USED_ITEMS) :
+ file_(file),
+ max_items_to_write_(max_items_to_write),
+ items_written_(0)
+ {}
+
+ void operator() (const recently_used_item* item)
+ {
+ if (items_written_++ < max_items_to_write_)
+ item->write_xml(file_);
+ }
+ private:
+ recently_used_file& file_;
+ int max_items_to_write_;
+ int items_written_;
+ };
+
+ //------------------------------------------------
+ const char* XML_HEADER = "<?xml version=\"1.0\"?>\n<RecentFiles>\n";
+ const char* XML_FOOTER = "</RecentFiles>";
+
+ //------------------------------------------------
+ // assumes that the list is ordered decreasing
+ void write_recently_used_items(
+ recently_used_file& file,
+ recently_used_item_list_t& item_list)
+ {
+ if (!item_list.empty())
+ {
+ file.truncate();
+ file.reset();
+
+ file.write(XML_HEADER, strlen(XML_HEADER));
+
+ std::for_each(
+ item_list.begin(),
+ item_list.end(),
+ recent_item_writer(file));
+
+ file.write(XML_FOOTER, strlen(XML_FOOTER));
+ }
+ }
+
+ //------------------------------------------------
+ struct delete_recently_used_item
+ {
+ void operator() (const recently_used_item* item) const
+ { delete item; }
+ };
+
+ //------------------------------------------------
+ void recently_used_item_list_clear(recently_used_item_list_t& item_list)
+ {
+ std::for_each(
+ item_list.begin(),
+ item_list.end(),
+ delete_recently_used_item());
+ item_list.clear();
+ }
+
+ //------------------------------------------------
+ class find_item_predicate
+ {
+ public:
+ find_item_predicate(const string_t& uri) :
+ uri_(uri)
+ {}
+
+ bool operator() (const recently_used_item* item)
+ { return (item->uri_ == uri_); }
+ private:
+ string_t uri_;
+ };
+
+ //------------------------------------------------
+ struct greater_recently_used_item
+ {
+ bool operator ()(const recently_used_item* lhs, const recently_used_item* rhs) const
+ { return (lhs->timestamp_ > rhs->timestamp_); }
+ };
+
+ //------------------------------------------------
+ const char* GROUP_OOO = "openoffice.org";
+ const char* GROUP_STAR_OFFICE = "staroffice";
+ const char* GROUP_STAR_SUITE = "starsuite";
+
+ //------------------------------------------------
+ void recently_used_item_list_add(
+ recently_used_item_list_t& item_list, const rtl::OUString& file_url, const rtl::OUString& mime_type)
+ {
+ rtl::OString f = rtl::OUStringToOString(file_url, RTL_TEXTENCODING_UTF8);
+
+ recently_used_item_list_t::iterator iter =
+ std::find_if(
+ item_list.begin(),
+ item_list.end(),
+ find_item_predicate(f.getStr()));
+
+ if (iter != item_list.end())
+ {
+ (*iter)->timestamp_ = time(NULL);
+
+ if (!(*iter)->has_group(GROUP_OOO))
+ (*iter)->groups_.push_back(GROUP_OOO);
+ if (!(*iter)->has_group(GROUP_STAR_OFFICE))
+ (*iter)->groups_.push_back(GROUP_STAR_OFFICE);
+ if (!(*iter)->has_group(GROUP_STAR_SUITE))
+ (*iter)->groups_.push_back(GROUP_STAR_SUITE);
+ }
+ else
+ {
+ string_container_t groups;
+ groups.push_back(GROUP_OOO);
+ groups.push_back(GROUP_STAR_OFFICE);
+ groups.push_back(GROUP_STAR_SUITE);
+
+ string_t uri(f.getStr());
+ string_t mimetype(rtl::OUStringToOString(mime_type, osl_getThreadTextEncoding()).getStr());
+
+ if (mimetype.length() == 0)
+ mimetype = "application/octet-stream";
+
+ item_list.push_back(new recently_used_item(uri, mimetype, groups));
+ }
+
+ // sort decreasing after the timestamp
+ // so that the newest items appear first
+ std::sort(
+ item_list.begin(),
+ item_list.end(),
+ greater_recently_used_item());
+ }
+
+ //##############################
+ bool update_recently_used_enabled()
+ {
+ rtl::OUString tmp;
+ osl_getEnvironment(ENVV_UPDATE_RECENTLY_USED.pData, &tmp.pData);
+ return (tmp.getLength() > 0);
+ }
+
+ //------------------------------------------------
+ struct cleanup_guard
+ {
+ cleanup_guard(recently_used_item_list_t& item_list) :
+ item_list_(item_list)
+ {}
+ ~cleanup_guard()
+ { recently_used_item_list_clear(item_list_); }
+
+ recently_used_item_list_t& item_list_;
+ };
+
+} // namespace private
+
+//###########################################
+/*
+ example (see http::www.freedesktop.org):
+ <?xml version="1.0"?>
+ <RecentFiles>
+ <RecentItem>
+ <URI>file:///home/federico/gedit.txt</URI>
+ <Mime-Type>text/plain</Mime-Type>
+ <Timestamp>1046485966</Timestamp>
+ <Groups>
+ <Group>gedit</Group>
+ </Groups>
+ </RecentItem>
+ <RecentItem>
+ <URI>file:///home/federico/gedit-2.2.0.tar.bz2</URI>
+ <Mime-Type>application/x-bzip</Mime-Type>
+ <Timestamp>1046209851</Timestamp>
+ <Private/>
+ <Groups>
+ </Groups>
+ </RecentItem>
+ </RecentFiles>
+*/
+extern "C" void add_to_recently_used_file_list(const rtl::OUString& file_url, const rtl::OUString& mime_type)
+{
+ try
+ {
+ recently_used_file ruf;
+ recently_used_item_list_t item_list;
+ cleanup_guard guard(item_list);
+
+ read_recently_used_items(ruf, item_list);
+ recently_used_item_list_add(item_list, file_url, mime_type);
+ write_recently_used_items(ruf, item_list);
+ }
+ catch(const char* ex)
+ {
+ OSL_ENSURE(false, ex);
+ }
+ catch(const xml_parser_exception&)
+ {
+ OSL_ENSURE(false, "XML parser error");
+ }
+ catch(const unknown_xml_format_exception&)
+ {
+ OSL_ENSURE(false, "XML format unknown");
+ }
+}
+
diff --git a/shell/source/unix/sysshell/recfile.map b/shell/source/unix/sysshell/recfile.map
new file mode 100755
index 000000000000..fa87f39161aa
--- /dev/null
+++ b/shell/source/unix/sysshell/recfile.map
@@ -0,0 +1,6 @@
+RECFILE_1_0_0 {
+ global:
+ add_to_recently_used_file_list;
+ local:
+ *;
+};