00001 /*************************************************************************** 00002 *cr 00003 *cr (C) Copyright 1995-2019 The Board of Trustees of the 00004 *cr University of Illinois 00005 *cr All Rights Reserved 00006 *cr 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * RCS INFORMATION: 00011 * 00012 * $RCSfile: FileChooserFltkMenu.C,v $ 00013 * $Author: johns $ $Locker: $ $State: Exp $ 00014 * $Revision: 1.57 $ $Date: 2020年07月08日 04:25:51 $ 00015 * 00016 *************************************************************************** 00017 * DESCRIPTION: 00018 * generated by Fast Light User Interface Designer (fluid) version 1.0100 00019 ***************************************************************************/ 00020 00021 #include <assert.h> 00022 #include <stdio.h> 00023 #include <FL/forms.H> 00024 #include <FL/Fl_Menu_.H> 00025 #include <FL/Fl_Round_Button.H> 00026 #include <FL/Fl_Multi_Browser.H> 00027 #include <FL/Fl_Int_Input.H> 00028 #include "FileChooserFltkMenu.h" 00029 #include "VMDApp.h" 00030 #include "Command.h" 00031 #include "molfile_plugin.h" 00032 #include "utilities.h" 00033 #include "Inform.h" 00034 00035 void FileChooserFltkMenu::browse_cb(Fl_Widget *w, void *v) { 00036 FileChooserFltkMenu *self = (FileChooserFltkMenu *)v; 00037 self->browse_files(); 00038 } 00039 00040 00041 void FileChooserFltkMenu::browse_files() { 00042 char mask[4096] = { 0 }; 00043 strcpy(mask, "*"); 00044 00045 const char *filetype = "All files"; 00046 int val = filetypechooser->value(); 00047 if (val) { 00048 const Fl_Menu_Item *menulist = filetypechooser->menu(); 00049 const char *extension = ((molfile_plugin_t *)menulist[val].user_data())->filename_extension; 00050 00051 if (extension) { 00052 int cnt = 0; // number of extensions added 00053 00054 // add all extensions to the filename selection mask 00055 char *extbuf = strdup(extension); 00056 int extlen = strlen(extbuf); 00057 char *extcur = extbuf; 00058 char *extnext = NULL; 00059 while ((extcur - extbuf) < extlen) { 00060 extnext = strchr(extcur, ','); // find next extension string 00061 if (extnext) { 00062 *extnext = '0円'; // NUL terminate this extension string 00063 extnext++; // step to beginning of next extension string 00064 } else { 00065 extnext = extbuf + extlen; // no more extensions, last time through 00066 } 00067 00068 if (cnt == 0) { 00069 sprintf(mask, "*.%s", extcur); // overwrite if the first extension 00070 } 00071 // XXX current file browser code doesn't do well with multiple 00072 // filename extensions, so we just drop subsequent ones 00073 #if 0 00074 else { 00075 char tmpmask[256] = { 0 }; 00076 sprintf(tmpmask, ",*.%s", extcur); 00077 strcat(mask, tmpmask); // concat subsequent extensions 00078 } 00079 #endif 00080 cnt++; 00081 00082 extcur = extnext; 00083 } 00084 free(extbuf); 00085 00086 filetype = ((molfile_plugin_t *)menulist[val].user_data())->name; 00087 } 00088 } 00089 char *result = app->vmd_choose_file( 00090 "Choose a molecule file", mask, filetype, 0); 00091 if (result) { 00092 add_file(result); 00093 delete [] result; 00094 } 00095 } 00096 00097 00098 void FileChooserFltkMenu::filenameinput_cb(Fl_Widget *w, void *v) { 00099 FileChooserFltkMenu *menu = (FileChooserFltkMenu *)v; 00100 menu->add_file(((Fl_Input *)w)->value()); 00101 } 00102 00103 00104 void FileChooserFltkMenu::add_file(const char *s) { 00105 if (!s) return; 00106 filenameinput->value(s); 00107 filenameinput->position(filenameinput->size(),0); 00108 00109 // Figure out what kind of file this is. If the file type chooser has 00110 // an item selected, don't change it. If it's "unknown", try to guess the 00111 // file type based on the filename extension. 00112 if (filetypechooser->value() > 0) { 00113 update_checkboxes(); 00114 return; // already have a file type. 00115 } 00116 filetypechooser->value(0); 00117 const char *filetype = app->guess_filetype(s); 00118 if (filetype) { 00119 const Fl_Menu_Item *menu = filetypechooser->menu(); 00120 if (menu != NULL) { 00121 // skip over the special "Automatically" item 00122 for (int j=1; j<menu->size()-2; j++) { 00123 const vmdplugin_t *plugin = (const vmdplugin_t *) menu[j].user_data(); 00124 if (plugin != NULL && !strcmp(plugin->name, filetype)) { 00125 filetypechooser->value(j); 00126 break; 00127 } 00128 } 00129 } 00130 } 00131 update_checkboxes(); 00132 } 00133 00134 00135 void FileChooserFltkMenu::update_molchooser(int selmol) { 00136 fill_fltk_molchooser(molchooser, app, "New Molecule"); 00137 if (selmol >= -1) molchooser->value(selmol+1); 00138 } 00139 00140 00141 // compare plugin names, for sorted display in the GUI 00142 static int compare_plugin_name(const void *p1, const void *p2) { 00143 return strcmp( (*(vmdplugin_t **)p1)->prettyname, (*(vmdplugin_t **)p2)->prettyname); 00144 } 00145 00146 00147 // Create the file type chooser from all the plugins. Set the chooser to 00148 // show "automatically", the default. Store the plugin in the user data of 00149 // the menu item. 00150 void FileChooserFltkMenu::update_filetypes() { 00151 PluginList plugins; 00152 int n; 00153 00154 // prepare the file type chooser and add the special "Automatically" choice 00155 filetypechooser->clear(); 00156 filetypechooser->add("Automatically"); 00157 00158 // 00159 // retrieve list of mol file reader plugins 00160 // 00161 n = app->list_plugins(plugins, "mol file reader"); 00162 00163 // sort plugins by their "pretty" name 00164 qsort(&(plugins[0]), n, sizeof(vmdplugin_t *), compare_plugin_name); 00165 00166 // add the plugins to the chooser, storing the plugin pointer in the menu 00167 for (int j=0; j<n; j++) { 00168 vmdplugin_t *p = plugins[j]; 00169 filetypechooser->add(p->prettyname, 0, NULL, p); // XXX valgrind FMR 00170 } 00171 00172 00173 // 00174 // retrieve list of mol file converter plugins 00175 // 00176 plugins.clear(); 00177 n = app->list_plugins(plugins, "mol file converter"); 00178 00179 // sort converter plugins by their "pretty" name 00180 qsort(&(plugins[0]), n, sizeof(vmdplugin_t *), compare_plugin_name); 00181 00182 // add the plugins to the chooser, storing the plugin pointer in the menu 00183 for (int k=0; k<n; k++) { 00184 vmdplugin_t *p = plugins[k]; 00185 char *buf = new char[strlen(p->prettyname)+16]; 00186 sprintf(buf, "Convert from:/%s", p->name); 00187 filetypechooser->add(buf, 0, NULL, p); // XXX valgrind FMR 00188 delete [] buf; 00189 } 00190 00191 // set the default value to "Automatically" 00192 filetypechooser->value(0); 00193 } 00194 00195 00196 void FileChooserFltkMenu::filetype_cb(Fl_Widget *w, void *v) { 00197 FileChooserFltkMenu *self = (FileChooserFltkMenu *)v; 00198 self->update_checkboxes(); 00199 } 00200 00201 00202 // reset the activity and value of checkboxes based on the current 00203 // value of filetypechooser 00204 void FileChooserFltkMenu::update_checkboxes() { 00205 has_structure = has_bonds = has_timesteps = has_graphics = 00206 has_volumetric = 0; 00207 timestepgroup->deactivate(); 00208 datasetbrowser->deactivate(); 00209 if (!filetypechooser->value()) return; 00210 00211 molfile_plugin_t *plugin = 00212 (molfile_plugin_t *)filetypechooser->mvalue()->user_data(); 00213 has_structure = (plugin->read_structure != NULL); 00214 has_bonds = (plugin->read_bonds != NULL); 00215 has_timesteps = (plugin->read_next_timestep != NULL); 00216 has_graphics = (plugin->read_rawgraphics != NULL); 00217 has_volumetric = (plugin->read_volumetric_metadata != NULL); 00218 00219 if (has_timesteps) { 00220 timestepgroup->activate(); 00221 firstinput->value("0"); 00222 lastinput->value("-1"); 00223 strideinput->value("1"); 00224 loadinbackgroundbutton->setonly(); 00225 } 00226 00227 if (has_volumetric) { 00228 datasetbrowser->activate(); 00229 datasetbrowser->clear(); 00230 const char *filename = filenameinput->value(); 00231 if (filename == NULL || !strlen(filename)) { 00232 msgInfo << "Can't show volumetric data; no filename selected yet" << sendmsg; 00233 return; 00234 } 00235 int natoms = -1; 00236 void *rv = plugin->open_file_read(filename, plugin->name, &natoms); 00237 if (!rv) { 00238 msgErr << "Unable to open file with plugin of type " << plugin->name << sendmsg; 00239 return; 00240 } 00241 molfile_volumetric_t *tmp; 00242 int nsets = -1; 00243 if (plugin->read_volumetric_metadata(rv, &nsets, &tmp)) { 00244 msgErr << "read_volumetric_metadata returned error" << sendmsg; 00245 plugin->close_file_read(rv); 00246 return; 00247 } 00248 if (nsets <= 0) { 00249 msgInfo << "No volumetric datasets found" << sendmsg; 00250 return; 00251 } 00252 for (int n=0; n<nsets; n++) { 00253 molfile_volumetric_t *v = tmp+n; 00254 char *buf = new char[strlen(v->dataname)+5]; 00255 sprintf(buf, "%d: %s", n+1, v->dataname); 00256 datasetbrowser->add(buf); 00257 delete [] buf; 00258 } 00259 datasetbrowser->select(1, datasetbrowser->size()); 00260 plugin->close_file_read(rv); 00261 } 00262 } 00263 00264 00265 void FileChooserFltkMenu::load_cb(Fl_Widget *, void *v) { 00266 FileChooserFltkMenu *self = (FileChooserFltkMenu *)v; 00267 self->load_file(self->filenameinput->value()); 00268 } 00269 00270 00271 void FileChooserFltkMenu::load_file(const char *filename) { 00272 const Fl_Menu_Item *menu = filetypechooser->menu(); 00273 00274 // Make sure a file is selected 00275 if (!filename || !strlen(filename)) { 00276 fl_alert("Please select a file."); 00277 return; 00278 } 00279 00280 // Make sure a plugin has been assigned 00281 if (filetypechooser->value() == 0) { 00282 const char *filetype = app->guess_filetype(filename); 00283 if (filetype) { 00284 if (menu != NULL) { 00285 // skip over the special "Automatically" item 00286 for (int j=1; j<menu->size()-2; j++) { 00287 const vmdplugin_t *plugin = (const vmdplugin_t *) menu[j].user_data(); 00288 if (plugin != NULL && !strcmp(plugin->name, filetype)) { 00289 filetypechooser->value(j); 00290 update_checkboxes(); 00291 break; 00292 } 00293 } 00294 } 00295 } else { 00296 fl_alert("Please select a file type."); 00297 return; 00298 } 00299 } 00300 00301 const vmdplugin_t *plugin = (const vmdplugin_t *) menu[filetypechooser->value()].user_data(); 00302 const char *filetype = plugin->name; 00303 00304 int molid = app->molecule_id(molchooser->value()-1); 00305 00306 FileSpec spec; 00307 sscanf(firstinput->value(), "%d", &spec.first); 00308 sscanf(lastinput->value(), "%d", &spec.last); 00309 sscanf(strideinput->value(), "%d", &spec.stride); 00310 if (spec.first < 0) spec.first = 0; 00311 if (spec.last >= 0 && spec.last < spec.first) spec.last = spec.first; 00312 if (spec.stride < 1) spec.stride = 1; 00313 spec.waitfor = allatoncebutton->value() ? 00314 FileSpec::WAIT_ALL : FileSpec::WAIT_BACK; 00315 00316 ResizeArray<int> setids; 00317 for (int j=0; j<datasetbrowser->size(); j++) { 00318 if (datasetbrowser->selected(j+1)) { 00319 setids.append(j); 00320 } 00321 } 00322 spec.nvolsets = setids.num(); 00323 spec.setids = &(setids[0]); 00324 00325 molid = app->molecule_load(molid, filename, filetype, &spec); 00326 spec.setids = NULL; // don't want FileSpec to delete the data! 00327 if (molid < 0) { 00328 fl_alert("Unable to load molecule."); 00329 return; 00330 } 00331 00332 // Clear the filename input, set the filetype back to automatic, and 00333 // change the molecule to the most recent one loaded, if any. If we 00334 // didn't do this, when you went to select a new molecule, the old 00335 // filetype would be retained, instead of being chosen from the filename 00336 // extension. It seems less surprising this way. 00337 00338 molchooser->value(0); 00339 for (int m=0; m<app->num_molecules(); m++) { 00340 if (molid == app->molecule_id(m)) { 00341 molchooser->value(m+1); 00342 } 00343 } 00344 filenameinput->value(""); 00345 filetypechooser->value(0); 00346 update_checkboxes(); 00347 } 00348 00349 00350 void FileChooserFltkMenu::make_window() { 00351 size(450,250); 00352 00353 { 00354 { Fl_Choice* o = molchooser = new Fl_Choice(109, 10, 320, 25, "Load files for: "); 00355 o->box(FL_THIN_UP_BOX); 00356 o->down_box(FL_BORDER_BOX); 00357 o->color(VMDMENU_CHOOSER_BG); 00358 o->selection_color(VMDMENU_CHOOSER_SEL); 00359 } 00360 filenameinput = new Fl_Input(85, 40, 270, 25, "Filename: "); 00361 filenameinput->callback(filenameinput_cb, this); 00362 filenameinput->when(FL_WHEN_ENTER_KEY_ALWAYS); 00363 filenameinput->selection_color(VMDMENU_VALUE_SEL); 00364 00365 VMDFLTKTOOLTIP(filenameinput, "Enter a filename, or a 4-character PDB accession code") 00366 00367 browsebutton = new Fl_Button(365, 40, 65, 25, "Browse..."); 00368 #if defined(VMDMENU_WINDOW) 00369 browsebutton->color(VMDMENU_WINDOW, FL_GRAY); 00370 #endif 00371 browsebutton->callback(browse_cb, this); 00372 browsebutton->when(FL_WHEN_ENTER_KEY_ALWAYS | FL_WHEN_RELEASE); 00373 { Fl_Choice* o = filetypechooser = new Fl_Choice(20, 90, 300, 25, "Determine file type:"); 00374 o->down_box(FL_BORDER_BOX); 00375 o->align(FL_ALIGN_TOP_LEFT); 00376 o->color(VMDMENU_CHOOSER_BG, VMDMENU_CHOOSER_SEL); 00377 o->callback(filetype_cb, this); 00378 00379 VMDFLTKTOOLTIP(o, "Select the correct file type (if not already guessed correctly") 00380 } 00381 { Fl_Button* o = loadbutton = new Fl_Button(345, 90, 85, 25, "Load"); 00382 #if defined(VMDMENU_WINDOW) 00383 o->color(VMDMENU_WINDOW, FL_GRAY); 00384 #endif 00385 VMDFLTKTOOLTIP(o, "Load the selected files") 00386 o->callback(load_cb, this); 00387 } 00388 { Fl_Group* o = timestepgroup = new Fl_Group(20, 145, 165, 95, "Frames: "); 00389 o->box(FL_ENGRAVED_FRAME); 00390 o->align(FL_ALIGN_TOP_LEFT); 00391 { Fl_Button* o = allatoncebutton = new Fl_Round_Button(30, 215, 150, 20, "Load all at once"); 00392 o->down_box(FL_ROUND_DOWN_BOX); 00393 o->type(FL_RADIO_BUTTON); 00394 } 00395 { Fl_Button* o = loadinbackgroundbutton = new Fl_Round_Button(30, 195, 150, 20, "Load in background"); 00396 o->down_box(FL_ROUND_DOWN_BOX); 00397 o->type(FL_RADIO_BUTTON); 00398 } 00399 { Fl_Input* o = firstinput = new Fl_Int_Input(25, 170, 45, 20, "First:"); 00400 o->align(FL_ALIGN_TOP); 00401 o->selection_color(VMDMENU_VALUE_SEL); 00402 } 00403 { Fl_Input* o = lastinput = new Fl_Int_Input(80, 170, 45, 20, "Last:"); 00404 o->align(FL_ALIGN_TOP); 00405 o->selection_color(VMDMENU_VALUE_SEL); 00406 } 00407 { Fl_Input* o = strideinput = new Fl_Int_Input(135, 170, 45, 20, "Stride:"); 00408 o->align(FL_ALIGN_TOP); 00409 o->selection_color(VMDMENU_VALUE_SEL); 00410 } 00411 o->end(); 00412 datasetbrowser = new Fl_Multi_Browser(195, 145, 235, 95, "Volumetric Datasets"); 00413 datasetbrowser->align(5); 00414 datasetbrowser->color(VMDMENU_BROWSER_BG, VMDMENU_BROWSER_SEL); 00415 } 00416 Fl_Window::end(); 00417 } 00418 } 00419 00420 00421 FileChooserFltkMenu::FileChooserFltkMenu(VMDApp *vmdapp) 00422 : VMDFltkMenu("files", "Molecule File Browser", vmdapp) { 00423 00424 make_window(); 00425 00426 command_wanted(Command::PLUGIN_UPDATE); 00427 command_wanted(Command::MOL_NEW); 00428 command_wanted(Command::MOL_DEL); 00429 command_wanted(Command::MOL_RENAME); 00430 00431 update_molchooser(); 00432 update_filetypes(); 00433 update_checkboxes(); 00434 } 00435 00436 00437 int FileChooserFltkMenu::selectmol(int molno) { 00438 update_molchooser(molno); 00439 return TRUE; 00440 } 00441 00442 00443 int FileChooserFltkMenu::act_on_command(int type, Command *cmd) { 00444 switch (type) { 00445 case Command::PLUGIN_UPDATE: 00446 update_filetypes(); 00447 break; 00448 case Command::MOL_NEW: 00449 case Command::MOL_DEL: 00450 case Command::MOL_RENAME: 00451 update_molchooser(); 00452 break; 00453 default: 00454 return 0; 00455 } 00456 return 1; 00457 }