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>
40 using namespace Gtkmm2ext
;
43 struct ModelColumns
: public TreeModel::ColumnRecord
{
49 TreeModelColumn
<bool> used
;
50 TreeModelColumn
<ustring
> text
;
51 TreeModelColumn
<jack_port_t
*> port
;
57 fill_it (RefPtr
<TreeStore
> model
, TreeView
* display
, ModelColumns
* columns
)
59 RefPtr
<TreeModel
> old
= display
->get_model();
60 display
->set_model (RefPtr
<TreeStore
>(0));
65 typedef map
<string
,vector
<pair
<string
,string
> > > PortMap
;
69 ports
= jack_get_ports (jack
, "", JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
);
75 /* find all the client names and group their ports into a list-by-client */
77 for (int n
= 0; ports
[n
]; ++n
) {
79 pair
<string
,vector
<pair
<string
,string
> > > newpair
;
80 pair
<string
,string
> strpair
;
81 std::pair
<PortMap::iterator
,bool> result
;
83 string str
= ports
[n
];
84 string::size_type pos
;
89 newpair
.first
= str
.substr (0, pos
);
90 portname
= str
.substr (pos
+1);
92 /* this may or may not succeed at actually inserting.
93 we don't care, however: we just want an iterator
94 that gives us either the inserted element or
95 the existing one with the same name.
98 result
= portmap
.insert (newpair
);
100 strpair
.first
= portname
;
101 strpair
.second
= str
;
103 result
.first
->second
.push_back (strpair
);
107 for (i
= portmap
.begin(); i
!= portmap
.end(); ++i
) {
109 /* i->first is a client name, i->second is a PortMap of all of its ports */
111 TreeModel::Row parent
= *(model
->append());
113 parent
[columns
->used
] = false;
114 parent
[columns
->text
] = i
->first
;
115 parent
[columns
->port
] = 0;
117 for (vector
<pair
<string
,string
> >::iterator s
= i
->second
.begin(); s
!= i
->second
.end(); ++s
) {
119 /* s->first is a port name */
121 TreeModel::Row row
= *(model
->append (parent
.children()));
123 row
[columns
->used
] = ((random()%2) == 1);
124 row
[columns
->text
] = s
->first
;
125 row
[columns
->port
] = (jack_port_t
*) random();
130 display
->set_model (old
);
134 selection_changed (RefPtr
<TreeModel
> model
, TreeView
* display
, ModelColumns
* columns
)
136 // TreeSelection::ListHandle_Path selection = display->get_selection()->get_selected_rows ();
138 // for (TreeSelection::ListHandle_Path::iterator x = selection.begin(); x != selection.end(); ++x) {
139 // cerr << "selected: " << (*(model->get_iter (*x)))[columns->text] << endl;
144 selection_filter (const RefPtr
<TreeModel
>& model
, const TreeModel::Path
& path
, bool yn
, ModelColumns
* columns
)
146 return (*(model
->get_iter (path
)))[columns
->port
] != 0;
150 object_drop (string type
, uint32_t cnt
, void** ptr
)
152 cerr
<< "Got an object drop of " << cnt
<< " pointer(s) of type " << type
<< endl
;
156 main (int argc
, char* argv
[])
158 Main
app (&argc
, &argv
);
162 Button
rescan ("rescan");
163 ScrolledWindow scrollerA
;
164 ScrolledWindow scrollerB
;
165 DnDTreeView displayA
;
166 DnDTreeView displayB
;
167 ModelColumns columns
;
169 if ((jack
= jack_client_new ("itest")) == NULL
) {
173 RefPtr
<TreeStore
> modelA
= TreeStore::create (columns
);
174 RefPtr
<TreeStore
> modelB
= TreeStore::create (columns
);
176 displayA
.set_model (modelA
);
177 displayA
.append_column ("Use", columns
.used
);
178 displayA
.append_column ("Source/Port", columns
.text
);
179 displayA
.set_reorderable (true);
180 displayA
.add_object_drag (columns
.port
.index(), "ports");
181 displayA
.signal_object_drop
.connect (ptr_fun (object_drop
));
183 displayA
.get_selection()->set_mode (SELECTION_MULTIPLE
);
184 displayA
.get_selection()->set_select_function (bind (ptr_fun (selection_filter
), &columns
));
185 displayA
.get_selection()->signal_changed().connect (bind (ptr_fun (selection_changed
), modelA
, &displayA
, &columns
));
187 displayB
.set_model (modelB
);
188 displayB
.append_column ("Use", columns
.used
);
189 displayB
.append_column ("Source/Port", columns
.text
);
190 displayB
.set_reorderable (true);
191 displayB
.add_object_drag (columns
.port
.index(), "ports");
192 displayB
.signal_object_drop
.connect (ptr_fun (object_drop
));
194 displayB
.get_selection()->set_mode (SELECTION_MULTIPLE
);
195 displayB
.get_selection()->set_select_function (bind (ptr_fun (selection_filter
), &columns
));
196 displayB
.get_selection()->signal_changed().connect (bind (ptr_fun (selection_changed
), modelB
, &displayB
, &columns
));
198 scrollerA
.add (displayA
);
199 scrollerB
.add (displayB
);
201 hpacker
.pack_start (scrollerA
);
202 hpacker
.pack_start (scrollerB
);
204 vpacker
.pack_start (hpacker
);
205 vpacker
.pack_start (rescan
, false, false);
208 win
.set_size_request (500, 400);
211 rescan
.signal_clicked().connect (bind (ptr_fun (fill_it
), modelA
, &displayA
, &columns
));
212 rescan
.signal_clicked().connect (bind (ptr_fun (fill_it
), modelB
, &displayB
, &columns
));
214 fill_it (modelA
, &displayA
, &columns
);
215 fill_it (modelB
, &displayB
, &columns
);
217 displayA
.expand_all();
218 displayB
.expand_all();
222 jack_client_close (jack
);