/* === S Y N F I G ========================================================= */
/*! \file dockdialog.cpp
** \brief Template File
**
** $Id$
**
** \legal
** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
** Copyright (c) 2007, 2008 Chris Moore
**
** This package 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 of
** the License, or (at your option) any later version.
**
** This package 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.
** \endlegal
*/
/* ========================================================================= */
/* === H E A D E R S ======================================================= */
#ifdef USING_PCH
# include "pch.h"
#else
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "app.h"
#include <sigc++/adaptors/hide.h>
#include "dockdialog.h"
#include "dockbook.h"
#include "dockmanager.h"
#include "toolbox.h"
#include "widget_compselect.h"
#include <synfig/general.h>
#include <synfig/uniqueid.h>
#include <gtkmm/table.h>
#include <sigc++/hide.h>
#include <sigc++/slot.h>
#include <sigc++/retype_return.h>
#include <sigc++/retype.h>
#include "canvasview.h"
#include <gtkmm/paned.h>
#include <gtkmm/box.h>
#include <synfigapp/main.h>
#include "general.h"
#endif
/* === U S I N G =========================================================== */
using namespace std;
using namespace etl;
using namespace synfig;
using namespace studio;
/* === M A C R O S ========================================================= */
#define GRAB_HINT_DATA(y,default) { \
String x; \
if(synfigapp::Main::settings().get_value(String("pref.")+y+"_hints",x)) \
{ \
set_type_hint((Gdk::WindowTypeHint)atoi(x.c_str())); \
} else {\
set_type_hint(default); \
} \
}
/* === G L O B A L S ======================================================= */
/* === P R O C E D U R E S ================================================= */
/* === M E T H O D S ======================================================= */
DockDialog::DockDialog():
Gtk::Window(Gtk::WINDOW_TOPLEVEL)
{
composition_selector_=false;
is_deleting=false;
is_horizontal=false;
last_dock_book=0;
box=0;
widget_comp_select=new Widget_CompSelect();
// Give ourselves an ID that is most likely unique
set_id(synfig::UniqueID().get_uid()^reinterpret_cast<long>(this));
set_role(strprintf("dock_dialog_%d",get_id()));
GRAB_HINT_DATA(
"dock_dialog",
#ifdef __APPLE__
Gdk::WINDOW_TYPE_HINT_NORMAL
#else
Gdk::WINDOW_TYPE_HINT_UTILITY
#endif
);
set_keep_above(false);
//! \todo can we set dialog windows transient for all normal windows, not just the toolbox?
//! paragraph 3 of http://standards.freedesktop.org/wm-spec/1.3/ar01s07.html suggests we can
// this seems to have bad effects on KDE, so leave it disabled by default
if(getenv("SYNFIG_TRANSIENT_DIALOGS"))
set_transient_for(*App::toolbox);
// Set up the window
//set_type_hint(Gdk::WINDOW_TYPE_HINT_UTILITY);
set_title(_("Dock Panel"));
// Register with the dock manager
App::dock_manager->dock_dialog_list_.push_back(this);
// connect our signals
signal_delete_event().connect(
sigc::hide(
sigc::mem_fun(*this,&DockDialog::close)
)
);
/*
App::signal_canvas_view_focus().connect(
sigc::hide(
sigc::mem_fun(
*this,
&DockDialog::refresh_accel_group
)
)
);
*/
add_accel_group(App::ui_manager()->get_accel_group());
App::signal_present_all().connect(sigc::mem_fun0(*this,&DockDialog::present));
}
DockDialog::~DockDialog()
{
empty_sig.disconnect();
is_deleting=true;
// Remove all of the dock books
for(;!dock_book_list.empty();dock_book_list.pop_front())
{
dock_book_list.front()->clear();
//! \todo Fix this UGLY HACK
// The following line really should be uncommented,
// but it causes crashes. Without it, a small
// memory hole is created--but at least it doesn't crash
// delete dock_book_list.front();
// Oddly enough, the following line should
// theoretically do the same thing after this
// class is destroyed, but it doesn't seem to
// cause a crash. It does, however, trigger this warning:
//
// A floating object was finalized. This means that someone
// called g_object_unref() on an object that had only a
// floating reference; the initial floating reference is not
// owned by anyone and must be removed with g_object_ref_sink().
//
// manage(dock_book_list.front());
}
// Remove us from the dock manager
if(App::dock_manager)try{
std::list<DockDialog*>::iterator iter;
for(iter=App::dock_manager->dock_dialog_list_.begin();iter!=App::dock_manager->dock_dialog_list_.end();++iter)
if(*iter==this)
{
App::dock_manager->dock_dialog_list_.erase(iter);
break;
}
}
catch(...)
{
synfig::warning("DockDialog::~DockDialog(): Exception thrown when trying to remove from dock manager...?");
}
delete widget_comp_select;
}
void
DockDialog::drop_on_prepend(const Glib::RefPtr<Gdk::DragContext>& context, int, int, const Gtk::SelectionData& selection_data, guint, guint time)
{
if ((selection_data.get_length() >= 0) && (selection_data.get_format() == 8))
{
Dockable& dockable(**reinterpret_cast<Dockable**>(const_cast<guint8*>(selection_data.get_data())));
prepend_dock_book()->add(dockable);
context->drag_finish(true, false, time);
return;
}
context->drag_finish(false, false, time);
}
void
DockDialog::drop_on_append(const Glib::RefPtr<Gdk::DragContext>& context, int, int, const Gtk::SelectionData& selection_data, guint, guint time)
{
if ((selection_data.get_length() >= 0) && (selection_data.get_format() == 8))
{
Dockable& dockable(**reinterpret_cast<Dockable**>(const_cast<guint8*>(selection_data.get_data())));
append_dock_book()->add(dockable);
context->drag_finish(true, false, time);
return;
}
context->drag_finish(false, false, time);
}
void
DockDialog::on_hide()
{
Gtk::Window::on_hide();
close();
}
DockBook*
DockDialog::prepend_dock_book()
{
if(is_deleting)return 0;
dock_book_list.push_front(new DockBook);
last_dock_book=dock_book_list.front();
last_dock_book->signal_empty().connect(
sigc::bind(
sigc::mem_fun(*this,&DockDialog::erase_dock_book),
last_dock_book
)
);
dock_book_sizes_.insert(dock_book_sizes_.begin(),225);
refresh();
return last_dock_book;
}
DockBook*
DockDialog::append_dock_book()
{
if(is_deleting)return 0;
dock_book_list.push_back(new DockBook);
last_dock_book=dock_book_list.back();
last_dock_book->signal_empty().connect(
sigc::bind(
sigc::mem_fun(*this,&DockDialog::erase_dock_book),
last_dock_book
)
);
last_dock_book->signal_changed().connect(
sigc::mem_fun(*this,&DockDialog::refresh_title)
);
last_dock_book->signal_changed().connect(
sigc::mem_fun(*this,&DockDialog::refresh_title)
);
dock_book_sizes_.push_back(225);
//last_dock_book->show();
refresh();
return last_dock_book;
}
void
DockDialog::erase_dock_book(DockBook* dock_book)
{
if(is_deleting)return;
std::list<DockBook*>::iterator iter;
for(iter=dock_book_list.begin();iter!=dock_book_list.end();++iter)
if(*iter==dock_book)
{
dock_book_list.erase(iter);
if(dock_book_list.empty())
{
last_dock_book=0;
close();
return;
}
else
{
if(last_dock_book==dock_book)
last_dock_book=dock_book_list.front();
}
refresh();
return;
}
}
void
DockDialog::refresh()
{
// synfig::info("dock_book_list.size()=%d",dock_book_list.size());
//remove();
if(dock_book_list.empty())
return;
if(box)delete box;
box=(manage(is_horizontal?(Gtk::Box*)new Gtk::HBox:(Gtk::Box*)new Gtk::VBox));
add(*box);
box->pack_start(*widget_comp_select,false,true);
Gtk::Button* append_button(manage(new Gtk::Button));
Gtk::Button* prepend_button(manage(new Gtk::Button));
std::list<Gtk::TargetEntry> listTargets;
listTargets.push_back( Gtk::TargetEntry("DOCK") );
append_button->drag_dest_set(listTargets);
prepend_button->drag_dest_set(listTargets);
append_button->signal_drag_data_received().connect(
sigc::mem_fun(*this,&DockDialog::drop_on_append)
);
prepend_button->signal_drag_data_received().connect(
sigc::mem_fun(*this,&DockDialog::drop_on_prepend)
);
box->pack_start(*prepend_button,false,true);
box->pack_end(*append_button,false,true);
//prepend_button->show();
//append_button->show();
panels_.clear();
if(dock_book_list.size()==1)
{
box->pack_start(get_dock_book(),true,true);
}
else
{
Gtk::Paned* parent(manage(is_horizontal?(Gtk::Paned*)new Gtk::HPaned:(Gtk::Paned*)new Gtk::VPaned));
panels_.push_back(parent);
if(panels_.size()<=dock_book_sizes_.size())
panels_.back()->set_position(dock_book_sizes_[panels_.size()-1]);
panels_.back()->property_position().signal_changed().connect(
sigc::mem_fun(*this,&DockDialog::rebuild_sizes)
);
//parent->show();
parent->add1(*dock_book_list.front());
//dock_book_list.front()->show();
box->pack_start(*parent,true,true);
std::list<DockBook*>::iterator iter,next;
for(next=dock_book_list.begin(),next++,iter=next++;next!=dock_book_list.end();iter=next++)
{
Gtk::Paned* current(manage(is_horizontal?(Gtk::Paned*)new Gtk::HPaned:(Gtk::Paned*)new Gtk::VPaned));
panels_.push_back(current);
if(panels_.size()<=dock_book_sizes_.size())
panels_.back()->set_position(dock_book_sizes_[panels_.size()-1]);
panels_.back()->property_position().signal_changed().connect(
sigc::mem_fun(*this,&DockDialog::rebuild_sizes)
);
parent->add2(*current);
current->add1(**iter);
//(*iter)->show();
//current->show();
parent=current;
}
parent->add2(**iter);
//(*iter)->show();
}
box->show_all();
if(!composition_selector_)
widget_comp_select->hide();
rebuild_sizes();
}
void
DockDialog::rebuild_sizes()
{
unsigned int i=0;
dock_book_sizes_.clear();
for(i=0;i<panels_.size();i++)
{
dock_book_sizes_.push_back(panels_[i]->get_position());
}
}
void
DockDialog::set_dock_book_sizes(const std::vector<int>& new_sizes)
{
unsigned int i=0;
for(i=0;i<panels_.size() && i<new_sizes.size();i++)
{
panels_[i]->set_position(new_sizes[i]);
}
dock_book_sizes_=new_sizes;
//rebuild_sizes();
}
void
DockDialog::refresh_accel_group()
{
/*
if(last_accel_group_)
{
last_accel_group_->unlock();
remove_accel_group(last_accel_group_);
last_accel_group_=Glib::RefPtr<Gtk::AccelGroup>();
}
etl::loose_handle<CanvasView> canvas_view(App::get_selected_canvas_view());
if(canvas_view)
{
last_accel_group_=canvas_view->get_accel_group();
last_accel_group_->lock();
add_accel_group(last_accel_group_);
}
*/
etl::loose_handle<CanvasView> canvas_view(App::get_selected_canvas_view());
if(canvas_view)
{
canvas_view->mainmenu.accelerate(*this);
}
}
bool
DockDialog::close()
{
if (getenv("SYNFIG_DEBUG_DESTRUCTORS"))
synfig::info("DockDialog::close(): Deleted");
empty_sig.disconnect();
//get_dock_book().clear();
delete this;
return true;
}
DockBook&
DockDialog::get_dock_book()
{
if(!last_dock_book)
return *append_dock_book();
return *last_dock_book;
}
const DockBook&
DockDialog::get_dock_book()const
{
return *last_dock_book;
}
synfig::String
DockDialog::get_contents()const
{
synfig::String ret;
std::list<DockBook*>::const_iterator iter;
for(iter=dock_book_list.begin();iter!=dock_book_list.end();++iter)
{
if(!ret.empty())
ret+=is_horizontal?" | ":" - ";
ret+=(*iter)->get_contents();
}
return ret;
}
void
DockDialog::set_contents(const synfig::String& z)
{
int x,y;
get_size(x,y);
synfig::String str(z);
while(!str.empty())
{
synfig::String::size_type separator=str.find_first_of('-');
{
synfig::String::size_type sep2=str.find_first_of('|');
if(separator!=synfig::String::npos || sep2!=synfig::String::npos)
{
if((separator==synfig::String::npos || sep2<separator) && sep2!=synfig::String::npos)
{
separator=sep2;
is_horizontal=true;
}
else
is_horizontal=false;
}
}
synfig::String book_contents;
if(separator==synfig::String::npos)
{
book_contents=str;
str.clear();
}
else
{
book_contents=String(str.begin(),str.begin()+separator);
str=String(str.begin()+separator+1,str.end());
}
try
{
append_dock_book()->set_contents(book_contents);
}catch(...) { }
}
resize(x,y);
}
void
DockDialog::set_composition_selector(bool x)
{
if(x==get_composition_selector())
return;
composition_selector_=x;
if(x)
widget_comp_select->show();
else
widget_comp_select->hide();
}
void
DockDialog::refresh_title()
{
if(is_deleting)return;
if(dock_book_list.size())
{
synfig::String title;
std::list<DockBook*>::const_iterator iter;
for(iter=dock_book_list.begin();iter!=dock_book_list.end();++iter)
{
if(!title.empty())
title+=", ";
title+=(*iter)->get_local_contents();
}
set_title(title);
}
else
set_title(_("Empty Dock Panel"));
}