Serenity Operating System
at hosted 206 lines 6.9 kB view raw
1/* 2 * Copyright (c) 2020, Emanuel Sprung <emanuel.sprung@gmail.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "BookmarksBarWidget.h" 28#include <LibGUI/Action.h> 29#include <LibGUI/BoxLayout.h> 30#include <LibGUI/Button.h> 31#include <LibGUI/Event.h> 32#include <LibGUI/JsonArrayModel.h> 33#include <LibGUI/Menu.h> 34#include <LibGUI/Model.h> 35#include <LibGUI/Widget.h> 36#include <LibGUI/Window.h> 37#include <LibGfx/Palette.h> 38 39BookmarksBarWidget::BookmarksBarWidget(const String& bookmarks_file, bool enabled) 40{ 41 set_layout<GUI::HorizontalBoxLayout>(); 42 layout()->set_spacing(0); 43 44 set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed); 45 set_preferred_size(0, 20); 46 47 if (!enabled) 48 set_visible(false); 49 50 m_additional = GUI::Button::construct(); 51 m_additional->set_button_style(Gfx::ButtonStyle::CoolBar); 52 m_additional->set_text(">"); 53 m_additional->set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed); 54 m_additional->set_preferred_size(14, 20); 55 m_additional->on_click = [&] { 56 if (m_additional_menu) { 57 m_additional_menu->popup(m_additional->relative_position().translated(relative_position().translated(m_additional->window()->position()))); 58 } 59 }; 60 61 m_separator = GUI::Widget::construct(); 62 63 Vector<GUI::JsonArrayModel::FieldSpec> fields; 64 fields.empend("title", "Title", Gfx::TextAlignment::CenterLeft); 65 fields.empend("url", "Url", Gfx::TextAlignment::CenterRight); 66 set_model(GUI::JsonArrayModel::create(bookmarks_file, move(fields))); 67 model()->update(); 68} 69 70BookmarksBarWidget::~BookmarksBarWidget() 71{ 72} 73 74void BookmarksBarWidget::set_model(RefPtr<GUI::Model> model) 75{ 76 if (model == m_model) 77 return; 78 m_model = move(model); 79 m_model->on_update = [&]() { 80 did_update_model(); 81 }; 82} 83 84void BookmarksBarWidget::resize_event(GUI::ResizeEvent& event) 85{ 86 Widget::resize_event(event); 87 update_content_size(); 88} 89 90void BookmarksBarWidget::did_update_model() 91{ 92 for (auto* child : child_widgets()) { 93 child->remove_from_parent(); 94 } 95 child_widgets().clear(); 96 97 m_bookmarks.clear(); 98 99 int width = 0; 100 for (int item_index = 0; item_index < model()->row_count(); ++item_index) { 101 102 auto title = model()->data(model()->index(item_index, 0)).to_string(); 103 auto url = model()->data(model()->index(item_index, 1)).to_string(); 104 105 Gfx::Rect rect { width, 0, font().width(title) + 32, height() }; 106 107 auto& button = add<GUI::Button>(); 108 m_bookmarks.append(button); 109 110 button.set_button_style(Gfx::ButtonStyle::CoolBar); 111 button.set_text(title); 112 button.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed); 113 button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-html.png")); 114 button.set_preferred_size(font().width(title) + 32, 20); 115 button.set_relative_rect(rect); 116 117 button.on_click = [title, url, this] { 118 if (on_bookmark_click) 119 on_bookmark_click(title, url); 120 }; 121 122 width += rect.width(); 123 } 124 125 add_child(*m_separator); 126 add_child(*m_additional); 127 128 update_content_size(); 129 update(); 130} 131 132void BookmarksBarWidget::update_content_size() 133{ 134 int x_position = 0; 135 m_last_visible_index = -1; 136 137 for (size_t i = 0; i < m_bookmarks.size(); ++i) { 138 auto& bookmark = m_bookmarks.at(i); 139 if (x_position + bookmark.width() > width()) { 140 m_last_visible_index = i; 141 break; 142 } 143 bookmark.set_x(x_position); 144 bookmark.set_visible(true); 145 x_position += bookmark.width(); 146 } 147 148 if (m_last_visible_index < 0) { 149 m_additional->set_visible(false); 150 } else { 151 // hide all items > m_last_visible_index and create new bookmarks menu for them 152 m_additional->set_visible(true); 153 m_additional_menu = GUI::Menu::construct("Additional Bookmarks"); 154 for (size_t i = m_last_visible_index; i < m_bookmarks.size(); ++i) { 155 auto& bookmark = m_bookmarks.at(i); 156 bookmark.set_visible(false); 157 m_additional_menu->add_action(GUI::Action::create(bookmark.text(), 158 Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-html.png"), 159 [&](auto&) { 160 bookmark.on_click(); 161 })); 162 } 163 } 164} 165 166bool BookmarksBarWidget::contains_bookmark(const String& url) 167{ 168 for (int item_index = 0; item_index < model()->row_count(); ++item_index) { 169 170 auto item_title = model()->data(model()->index(item_index, 0)).to_string(); 171 auto item_url = model()->data(model()->index(item_index, 1)).to_string(); 172 if (item_url == url) { 173 return true; 174 } 175 } 176 return false; 177} 178 179bool BookmarksBarWidget::remove_bookmark(const String& url) 180{ 181 for (int item_index = 0; item_index < model()->row_count(); ++item_index) { 182 183 auto item_title = model()->data(model()->index(item_index, 0)).to_string(); 184 auto item_url = model()->data(model()->index(item_index, 1)).to_string(); 185 if (item_url == url) { 186 auto& json_model = *static_cast<GUI::JsonArrayModel*>(model()); 187 json_model.remove(item_index); 188 return true; 189 } 190 } 191 192 return false; 193} 194bool BookmarksBarWidget::add_bookmark(const String& url, const String& title) 195{ 196 Vector<JsonValue> values; 197 values.append(title); 198 values.append(url); 199 200 auto& json_model = *static_cast<GUI::JsonArrayModel*>(model()); 201 if (json_model.add(move(values))) { 202 json_model.store(); 203 return true; 204 } 205 return false; 206}