1 // This file is part of GtkEveMon.
2 //
3 // GtkEveMon is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // You should have received a copy of the GNU General Public License
9 // along with GtkEveMon. If not, see <http://www.gnu.org/licenses/>.
10 
11 #include <gtkmm.h>
12 
13 #include "util/helpers.h"
14 #include "api/evetime.h"
15 #include "api/apiskilltree.h"
16 #include "api/apiskillqueue.h"
17 #include "bits/config.h"
18 #include "imagestore.h"
19 #include "gtkhelpers.h"
20 #include "gtkdefines.h"
21 #include "gtkskillqueue.h"
22 #include "guiskill.h"
23 
GtkSkillQueueViewCols(Gtk::TreeView * view,GtkSkillQueueColumns * cols)24 GtkSkillQueueViewCols::GtkSkillQueueViewCols (Gtk::TreeView* view,
25     GtkSkillQueueColumns* cols)
26   : GtkColumnsBase(view),
27     position("Position", cols->queue_pos),
28     start_sp("Start SP", cols->start_sp),
29     end_sp("Dest SP", cols->end_sp),
30     start_time("Start time", cols->start_time),
31     end_time("Finish time", cols->end_time),
32     duration("Duration", cols->duration),
33     training("Training", cols->training),
34     attribs("Attribs", cols->attribs)
35 {
36   this->skill_name.set_title("Skill name");
37   this->skill_name.pack_start(cols->skill_icon, false);
38   this->skill_name.pack_start(cols->skill_name, true);
39 
40   this->position.set_resizable(false);
41 
42   this->append_column(&this->position,
43       GtkColumnOptions(false, true, true, ImageStore::columnconf[1]));
44   this->append_column(&this->skill_name, GtkColumnOptions(false, false, true));
45   this->append_column(&this->start_sp, GtkColumnOptions(true, false, true));
46   this->append_column(&this->end_sp, GtkColumnOptions(true, false, true));
47   this->append_column(&this->start_time, GtkColumnOptions(true, false, true));
48   this->append_column(&this->end_time, GtkColumnOptions(true, false, true));
49   this->append_column(&this->duration, GtkColumnOptions(true, false, true));
50   this->append_column(&this->training, GtkColumnOptions(true, false, true));
51   this->append_column(&this->attribs, GtkColumnOptions(true, false, true));
52 
53   this->position.get_first_cell()->set_property("xalign", 1.0f);
54   this->skill_name.set_expand(true);
55   this->start_sp.get_first_cell()->set_property("xalign", 1.0f);
56   this->end_sp.get_first_cell()->set_property("xalign", 1.0f);
57 }
58 
59 /* ================================================================ */
60 
GtkSkillQueue(void)61 GtkSkillQueue::GtkSkillQueue (void)
62   : queue_store(Gtk::ListStore::create(queue_cols)),
63     queue_view(queue_store),
64     queue_view_cols(&queue_view, &queue_cols)
65 {
66   /* Setup EVE API fetcher. */
67   Gtk::ScrolledWindow* scwin = MK_SCWIN;
68   scwin->add(this->queue_view);
69   scwin->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS);
70   scwin->set_shadow_type(Gtk::SHADOW_ETCHED_IN);
71 
72   this->queue_view_cols.position.signal_clicked().connect(sigc::mem_fun
73       (this->queue_view_cols, &GtkColumnsBase::toggle_edit_context));
74 
75   this->set_border_width(5);
76   this->pack_start(*scwin, true, true, 0);
77 
78   //this->queue_view_cols.set_format("+0 +1 +2 +3 +4 +5 +6 +7");
79   this->init_from_config();
80   this->queue_view_cols.setup_columns_normal();
81 
82   this->queue_view.signal_row_activated().connect(sigc::mem_fun
83                 (*this, &GtkSkillQueue::on_row_activated));
84 }
85 
86 /* ---------------------------------------------------------------- */
87 
~GtkSkillQueue(void)88 GtkSkillQueue::~GtkSkillQueue (void)
89 {
90   this->store_to_config();
91   Config::save_to_file();
92 }
93 
94 /* ---------------------------------------------------------------- */
95 
96 void
set_character(CharacterPtr character)97 GtkSkillQueue::set_character (CharacterPtr character)
98 {
99   this->character = character;
100   this->character->signal_skill_queue_updated().connect
101       (sigc::mem_fun(*this, &GtkSkillQueue::on_apidata_available));
102   this->character->signal_cached_warning().connect(sigc::bind
103       (sigc::mem_fun(*this, &GtkSkillQueue::on_api_problems), true));
104   this->character->signal_request_error().connect(sigc::bind
105       (sigc::mem_fun(*this, &GtkSkillQueue::on_api_problems), false));
106 }
107 
108 /* ---------------------------------------------------------------- */
109 
110 void
refresh(void)111 GtkSkillQueue::refresh (void)
112 {
113     if (this->character->valid_training_sheet())
114         this->on_apidata_available();
115     else
116         this->character->request_skillqueue();
117 }
118 
119 /* ---------------------------------------------------------------- */
120 
121 void
init_from_config(void)122 GtkSkillQueue::init_from_config (void)
123 {
124   ConfSectionPtr skillqueue = Config::conf.get_section("skillqueue");
125   ConfValuePtr columns_format = skillqueue->get_value("columns_format");
126   this->queue_view_cols.set_format(**columns_format);
127 }
128 
129 /* ---------------------------------------------------------------- */
130 
131 void
store_to_config(void)132 GtkSkillQueue::store_to_config (void)
133 {
134   ConfSectionPtr skillqueue = Config::conf.get_section("skillqueue");
135   ConfValuePtr columns_format = skillqueue->get_value("columns_format");
136   columns_format->set(this->queue_view_cols.get_format());
137 }
138 
139 /* ---------------------------------------------------------------- */
140 
141 #include <iostream>
142 
143 void
on_apidata_available(void)144 GtkSkillQueue::on_apidata_available (void)
145 {
146   ApiSkillQueuePtr sq = this->character->sq;
147 
148   /* Debugging. */
149   //sq->debug_dump();
150 
151   /* FIXME: Pay attention to training times. */
152 
153   this->queue_store->clear();
154   ApiSkillTreePtr tree = ApiSkillTree::request();
155   time_t training = 0;
156   for (std::size_t i = 0; i < sq->queue.size(); ++i)
157   {
158     ApiSkillQueueItem const& item = sq->queue[i];
159 
160     time_t duration = item.end_time_t - item.start_time_t;
161     //time_t duration = item.end_time_t - EveTime::get_eve_time(); //FIX?
162     training += duration;
163 
164     ApiSkill const* skill = tree->get_skill_for_id(item.skill_id);
165     std::string skill_name = (skill == 0
166         ? Helpers::get_string_from_int(item.skill_id) : skill->name);
167     skill_name += " ";
168     skill_name += Helpers::get_roman_from_int(item.to_level);
169 
170     Gtk::TreeModel::Row row = *this->queue_store->append();
171     row[this->queue_cols.queue_pos] = item.queue_pos;
172     row[this->queue_cols.skill_name] = skill_name;
173     row[this->queue_cols.skill_icon] = ImageStore::skillicons[1];
174     row[this->queue_cols.start_sp] = item.start_sp;
175     row[this->queue_cols.end_sp] = item.end_sp;
176     row[this->queue_cols.start_time]
177         = EveTime::get_local_time_string(item.start_time_t, true);
178     row[this->queue_cols.end_time]
179         = EveTime::get_local_time_string(item.end_time_t, true);
180     row[this->queue_cols.duration]
181         = EveTime::get_string_for_timediff(duration, true);
182     row[this->queue_cols.training]
183         = EveTime::get_string_for_timediff(training, true);
184 
185     Glib::ustring attribs;
186     attribs += ApiSkillTree::get_attrib_short_name(skill->primary);
187     attribs += " / ";
188     attribs += ApiSkillTree::get_attrib_short_name(skill->secondary);
189     row[this->queue_cols.attribs]
190       = attribs;
191 
192     row[this->queue_cols.skill_id] = item.skill_id;
193   }
194 }
195 
196 /* ---------------------------------------------------------------- */
197 
198 void
on_api_problems(EveApiDocType sheet,std::string error,bool cache)199 GtkSkillQueue::on_api_problems (EveApiDocType sheet,
200     std::string error, bool cache)
201 {
202   if (sheet != API_DOCTYPE_SKILLQUEUE)
203     return;
204   this->raise_error(error, cache);
205 }
206 
207 /* ---------------------------------------------------------------- */
208 
209 void
raise_error(std::string const & error,bool cached)210 GtkSkillQueue::raise_error (std::string const& error, bool cached)
211 {
212   Gtk::MessageType message_type;
213   Glib::ustring message;
214   if (cached)
215   {
216     message = "Using cached version of the skill queue!";
217     message_type = Gtk::MESSAGE_WARNING;
218   }
219   else
220   {
221     message = "Error retrieving skill queue!";
222     message_type = Gtk::MESSAGE_ERROR;
223   }
224 
225   Gtk::Window* win = (Gtk::Window*)this->get_toplevel();
226   Gtk::MessageDialog md(*win, message, false, message_type, Gtk::BUTTONS_OK);
227   md.set_secondary_text("There was an error while requesting the skill "
228       "queue from the EVE API. The EVE API is either offline, or the "
229       "requested document is not understood by GtkEveMon. "
230       "The error message is:\n\n" + GtkHelpers::locale_to_utf8(error));
231   md.set_title("Error - GtkEveMon");
232   md.run();
233 }
234 
on_row_activated(Gtk::TreeModel::Path const & path,Gtk::TreeViewColumn *)235 void GtkSkillQueue::on_row_activated(Gtk::TreeModel::Path const& path,
236     Gtk::TreeViewColumn* /*col*/)
237 {
238   Gtk::TreeModel::iterator iter = this->queue_store->get_iter(path);
239   Gtk::TreeModel::Row row = *iter;
240   int skill_id = row[this->queue_cols.skill_id];
241   if (skill_id >= 0)
242   {
243     GuiSkill* skillgui = new GuiSkill();
244     skillgui->set_skill(skill_id);
245   }
246 }
247