2 Copyright (C) 2000-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <gtkmm/main.h>
26 #include <gtkmm/window.h>
27 #include <gtkmm/box.h>
28 #include <gtkmm/scrolledwindow.h>
29 #include <gtkmm2ext/dndtreeview.h>
30 #include <gtkmm/treemodel.h>
31 #include <gtkmm/treestore.h>
32 #include <gtkmm/treepath.h>
33 #include <gtkmm/button.h>
34 #include <gtkmm/window.h>
35 #include <jack/jack.h>
39 using namespace Gtkmm2ext
;
42 struct ModelColumns
: public TreeModel::ColumnRecord
{
48 TreeModelColumn
<bool> used
;
49 TreeModelColumn
<ustring
> text
;
50 TreeModelColumn
<jack_port_t
*> port
;
56 fill_it (RefPtr
<TreeStore
> model
, TreeView
* display
, ModelColumns
* columns
)
58 RefPtr
<TreeModel
> old
= display
->get_model();
59 display
->set_model (RefPtr
<TreeStore
>(0));
64 typedef map
<string
,vector
<pair
<string
,string
> > > PortMap
;
68 ports
= jack_get_ports (jack
, "", JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
);
74 /* find all the client names and group their ports into a list-by-client */
76 for (int n
= 0; ports
[n
]; ++n
) {
78 pair
<string
,vector
<pair
<string
,string
> > > newpair
;
79 pair
<string
,string
> strpair
;
80 std::pair
<PortMap::iterator
,bool> result
;
82 string str
= ports
[n
];
83 string::size_type pos
;
88 newpair
.first
= str
.substr (0, pos
);
89 portname
= str
.substr (pos
+1);
91 /* this may or may not succeed at actually inserting.
92 we don't care, however: we just want an iterator
93 that gives us either the inserted element or
94 the existing one with the same name.
97 result
= portmap
.insert (newpair
);
99 strpair
.first
= portname
;
100 strpair
.second
= str
;
102 result
.first
->second
.push_back (strpair
);
106 for (i
= portmap
.begin(); i
!= portmap
.end(); ++i
) {
108 /* i->first is a client name, i->second is a PortMap of all of its ports */
110 TreeModel::Row parent
= *(model
->append());
112 parent
[columns
->used
] = false;
113 parent
[columns
->text
] = i
->first
;
114 parent
[columns
->port
] = 0;
116 for (vector
<pair
<string
,string
> >::iterator s
= i
->second
.begin(); s
!= i
->second
.end(); ++s
) {
118 /* s->first is a port name */
120 TreeModel::Row row
= *(model
->append (parent
.children()));
122 row
[columns
->used
] = ((random()%2) == 1);
123 row
[columns
->text
] = s
->first
;
124 row
[columns
->port
] = (jack_port_t
*) random();
129 display
->set_model (old
);
133 selection_changed (RefPtr
<TreeModel
> model
, TreeView
* display
, ModelColumns
* columns
)
135 // TreeSelection::ListHandle_Path selection = display->get_selection()->get_selected_rows ();
137 // for (TreeSelection::ListHandle_Path::iterator x = selection.begin(); x != selection.end(); ++x) {
138 // cerr << "selected: " << (*(model->get_iter (*x)))[columns->text] << endl;
143 selection_filter (const RefPtr
<TreeModel
>& model
, const TreeModel::Path
& path
, bool yn
, ModelColumns
* columns
)
145 return (*(model
->get_iter (path
)))[columns
->port
] != 0;
149 object_drop (string type
, uint32_t cnt
, void** ptr
)
151 cerr
<< "Got an object drop of " << cnt
<< " pointer(s) of type " << type
<< endl
;
155 main (int argc
, char* argv
[])
157 Main
app (&argc
, &argv
);
161 Button
rescan ("rescan");
162 ScrolledWindow scrollerA
;
163 ScrolledWindow scrollerB
;
164 DnDTreeView displayA
;
165 DnDTreeView displayB
;
166 ModelColumns columns
;
168 if ((jack
= jack_client_new ("itest")) == NULL
) {
172 RefPtr
<TreeStore
> modelA
= TreeStore::create (columns
);
173 RefPtr
<TreeStore
> modelB
= TreeStore::create (columns
);
175 displayA
.set_model (modelA
);
176 displayA
.append_column ("Use", columns
.used
);
177 displayA
.append_column ("Source/Port", columns
.text
);
178 displayA
.set_reorderable (true);
179 displayA
.add_object_drag (columns
.port
.index(), "ports");
180 displayA
.signal_object_drop
.connect (ptr_fun (object_drop
));
182 displayA
.get_selection()->set_mode (SELECTION_MULTIPLE
);
183 displayA
.get_selection()->set_select_function (sigc::bind (ptr_fun (selection_filter
), &columns
));
184 displayA
.get_selection()->signal_changed().connect (sigc::bind (ptr_fun (selection_changed
), modelA
, &displayA
, &columns
));
186 displayB
.set_model (modelB
);
187 displayB
.append_column ("Use", columns
.used
);
188 displayB
.append_column ("Source/Port", columns
.text
);
189 displayB
.set_reorderable (true);
190 displayB
.add_object_drag (columns
.port
.index(), "ports");
191 displayB
.signal_object_drop
.connect (ptr_fun (object_drop
));
193 displayB
.get_selection()->set_mode (SELECTION_MULTIPLE
);
194 displayB
.get_selection()->set_select_function (sigc::bind (ptr_fun (selection_filter
), &columns
));
195 displayB
.get_selection()->signal_changed().connect (sigc::bind (ptr_fun (selection_changed
), modelB
, &displayB
, &columns
));
197 scrollerA
.add (displayA
);
198 scrollerB
.add (displayB
);
200 hpacker
.pack_start (scrollerA
);
201 hpacker
.pack_start (scrollerB
);
203 vpacker
.pack_start (hpacker
);
204 vpacker
.pack_start (rescan
, false, false);
207 win
.set_size_request (500, 400);
210 rescan
.signal_clicked().connect (sigc::bind (ptr_fun (fill_it
), modelA
, &displayA
, &columns
));
211 rescan
.signal_clicked().connect (sigc::bind (ptr_fun (fill_it
), modelB
, &displayB
, &columns
));
213 fill_it (modelA
, &displayA
, &columns
);
214 fill_it (modelB
, &displayB
, &columns
);
216 displayA
.expand_all();
217 displayB
.expand_all();
221 jack_client_close (jack
);