ConfigEditor.pm.svn-base
上传用户:market2
上传日期:2018-11-18
资源大小:18786k
文件大小:8k
源码类别:

外挂编程

开发平台:

Windows_Unix

  1. package Interface::Wx::ConfigEditor;
  2. use strict;
  3. use Wx ':everything';
  4. use Wx::Event qw(EVT_LISTBOX);
  5. use base qw(Wx::Panel);
  6. use Interface::Wx::ConfigEditor;
  7. use encoding 'utf8';
  8. sub new {
  9. my $class = shift;
  10. my ($parent, $id) = @_;
  11. my $self;
  12. $self = $class->SUPER::new($parent, $id);
  13. my $hsizer = $self->{hsizer} = new Wx::BoxSizer(wxHORIZONTAL);
  14. $self->SetSizer($hsizer);
  15. my $vsizer = new Wx::BoxSizer(wxVERTICAL);
  16. $hsizer->Add($vsizer, 0, wxGROW | wxRIGHT, 8);
  17. my $label = new Wx::StaticText($self, -1, 'Categories:');
  18. $vsizer->Add($label, 0);
  19. my $list = $self->{list} = new Wx::ListBox($self, 81, wxDefaultPosition, wxDefaultSize,
  20. [], wxLB_SINGLE);
  21. $vsizer->Add($list, 1);
  22. $self->_displayIntro;
  23. EVT_LISTBOX($self, 81, &_selectCategory);
  24. return $self;
  25. }
  26. sub setConfig {
  27. my $self = shift;
  28. my $hash = shift;
  29. $self->{hash} = $hash;
  30. }
  31. sub addCategory {
  32. my ($self, $name, $editor, $keys) = @_;
  33. $self->{list}->Append($name);
  34. $self->{categories}{$name}{editor} = $editor;
  35. $self->{categories}{$name}{keys} = $keys;
  36. }
  37. sub revert {
  38. my $self = shift;
  39. return unless ($self->{backup} && $self->{editor});
  40. foreach my $key (keys %{$self->{backup}}) {
  41. my $val1 = $self->{editor}->getValue($key);
  42. if (defined($val1) && $val1 ne $self->{backup}{$key}) {
  43. $self->{editor}->setValue($key, $self->{backup}{$key});
  44. }
  45. }
  46. }
  47. sub onChange {
  48. my ($self, $callback) = @_;
  49. $self->{callback} = $callback;
  50. $self->{editor}->onChange($callback) if ($self->{editor});
  51. }
  52. sub onRevertEnable {
  53. my ($self, $callback) = @_;
  54. $self->{revertEnableCallback} = $callback;
  55. }
  56. sub _displayIntro {
  57. my $self = shift;
  58. my $label = $self->{intro} = new Wx::StaticText($self, -1,
  59. 'Click on one of the categories on the left to begin.',
  60. wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
  61. $self->{hsizer}->Add($label, 1, wxALIGN_CENTER);
  62. }
  63. sub _selectCategory {
  64. my ($self, $event) = @_;
  65. my $list = $self->{list};
  66. my $name = $list->GetString($list->GetSelection);
  67. return unless ($self->{selectedCategory} ne $name);
  68. my $editorName = $self->{categories}{$name}{editor};
  69. my $editor;
  70. if ($editorName) {
  71. $editor = eval "Interface::Wx::ConfigEditor::${editorName}->new($self, -1);";
  72. }
  73. if (!$editor) {
  74. $editor = Interface::Wx::ConfigEditor::Grid->new($self, -1);
  75. }
  76. if ($self->{intro}) {
  77. $self->{hsizer}->Detach($self->{intro});
  78. $self->{intro}->Destroy;
  79. delete $self->{intro};
  80. } elsif ($self->{editor}) {
  81. $self->{hsizer}->Detach($self->{editor});
  82. $self->{editor}->Destroy;
  83. delete $self->{editor};
  84. }
  85. $editor->onChange($self->{callback});
  86. $self->{backup} = {%{$self->{hash}}};
  87. if ($self->{categories}{$name}{keys}) {
  88. my %hash;
  89. foreach (@{$self->{categories}{$name}{keys}}) {
  90. $hash{$_} = $self->{hash}{$_};
  91. }
  92. $editor->setConfig(%hash);
  93. } else {
  94. $editor->setConfig($self->{hash});
  95. }
  96. if ($self->{revertEnableCallback}) {
  97. $self->{revertEnableCallback}->(0);
  98. $editor->onRevertEnable($self->{revertEnableCallback});
  99. }
  100. $self->{editor} = $editor;
  101. $self->{hsizer}->Add($editor, 1, wxGROW);
  102. $self->Layout;
  103. $self->{selectedCategory} = $name;
  104. $event->Skip;
  105. }
  106. package Interface::Wx::ConfigEditor::Grid;
  107. use Wx ':everything';
  108. use Wx::Grid;
  109. use Wx::Event qw(EVT_GRID_CELL_CHANGE EVT_GRID_CELL_LEFT_CLICK EVT_TIMER EVT_BUTTON);
  110. use Wx::Html;
  111. use base qw(Wx::Panel);
  112. use Utils::HttpReader;
  113. our $manual;
  114. sub new {
  115. my $class = shift;
  116. my ($parent, $id) = @_;
  117. my $style = wxTAB_TRAVERSAL;
  118. $style |= wxSUNKEN_BORDER if ($^O ne 'MSWin32');
  119. my $self = $class->SUPER::new($parent, $id, wxDefaultPosition, wxDefaultSize,
  120. $style);
  121. my $sizer = new Wx::BoxSizer(wxVERTICAL);
  122. $self->SetSizer($sizer);
  123. my $splitter = new Wx::SplitterWindow($self, -1, wxDefaultPosition, wxDefaultSize,
  124. wxSP_3D | wxSP_LIVE_UPDATE);
  125. $sizer->Add($splitter, 1, wxGROW);
  126. my $grid = $self->{grid} = new Wx::Grid($splitter, -1);
  127. $grid->CreateGrid(0, 2);
  128. $grid->SetRowLabelSize(0);
  129. $grid->SetColLabelSize(22);
  130. $grid->SetColLabelValue(0, "Option");
  131. $grid->SetColLabelValue(1, "Value");
  132. $grid->EnableDragRowSize(0);
  133. EVT_GRID_CELL_LEFT_CLICK($grid, sub { $self->_onClick(@_); });
  134. EVT_GRID_CELL_CHANGE($grid, sub { $self->_changed(@_); });
  135. if (!defined $manual) {
  136. $self->downloadManual($parent);
  137. }
  138. my $html = $self->{html} = new Wx::HtmlWindow($splitter, -1);
  139. if ($^O ne 'MSWin32') {
  140. $html->SetFonts('Bitstream Vera Sans', 'Bitstream Vera Sans Mono',
  141. [10, 10, 10, 10, 10, 10, 10]);
  142. }
  143. $splitter->SplitHorizontally($grid, $html);
  144. $splitter->SetSashPosition(-100);
  145. return $self;
  146. }
  147. sub downloadManual {
  148. my ($self, $parent) = @_;
  149. my ($file, $f, $time);
  150. $file = Settings::getControlFilename("manual.html");
  151. $time = (stat($file))[9];
  152. # Download manual if it hasn't been downloaded yet,
  153. # or if the local copy is more than 3 days old
  154. if ($file && time - $time <= 60 * 60 * 24 * 3 && open($f, "<", $file)) {
  155. binmode F;
  156. local($/);
  157. $manual = <$f>;
  158. close $f;
  159. } else {
  160. my $dialog = new Wx::Dialog($parent->GetGrandParent, -1, "Downloading");
  161. my $sizer = new Wx::BoxSizer(wxVERTICAL);
  162. my $label = new Wx::StaticText($dialog, -1, "Downloading manual, please wait...");
  163. $sizer->Add($label, 1, wxGROW | wxALL, 8);
  164. my $gauge = new Wx::Gauge($dialog, -1, 100, wxDefaultPosition,
  165. [0, 16], wxGA_SMOOTH | wxGA_HORIZONTAL);
  166. $sizer->Add($gauge, 0, wxGROW | wxLEFT | wxRIGHT, 8);
  167. my $button = new Wx::Button($dialog, 475, '&Cancel');
  168. $sizer->Add($button, 0, wxALL | wxALIGN_CENTRE_HORIZONTAL, 8);
  169. EVT_BUTTON($dialog, 475, sub {
  170. $dialog->Close;
  171. });
  172. $dialog->SetSizerAndFit($sizer);
  173. my $timer = new Wx::Timer($dialog, 476);
  174. my $downloader = new StdHttpReader('http://openkore.sourceforge.net/manual/config/');
  175. EVT_TIMER($dialog, 476, sub {
  176. if ($downloader->getStatus() != HttpReader::CONNECTING) {
  177. my $size = $downloader->getSize();
  178. my $progress = 0;
  179. if ($size > 0) {
  180. my $len = 0;
  181. $size->getData($len);
  182. $progress = $len / $size * 100;
  183. }
  184. $gauge->SetValue($progress);
  185. }
  186. if ($downloader->getStatus() == HttpReader::DONE) {
  187. my $len;
  188. $gauge->SetValue(100);
  189. $dialog->Close;
  190. $manual = $downloader->getData($len);
  191. $timer->Destroy;
  192. undef $timer;
  193. } elsif ($downloader->getStatus() == HttpReader::ERROR) {
  194. $gauge->SetValue(100);
  195. $dialog->Close;
  196. $timer->Destroy;
  197. undef $timer;
  198. }
  199. });
  200. $timer->Start(100);
  201. $dialog->ShowModal;
  202. if (!defined $file) {
  203. my @folders = Settings::getControlFolders();
  204. $file = "$folders[0]/manual.html";
  205. }
  206. if ($manual && open($f, ">", $file)) {
  207. binmode F;
  208. print $f $manual;
  209. close $f;
  210. }
  211. }
  212. }
  213. sub onChange {
  214. my ($self, $callback) = @_;
  215. $self->{onChanged} = $callback;
  216. }
  217. sub onRevertEnable {
  218. my ($self, $callback) = @_;
  219. $self->{revertEnableCallback} = $callback;
  220. }
  221. sub setConfig {
  222. my ($self, $hash) = @_;
  223. my $grid = $self->{grid};
  224. my @keys = sort keys %{$hash};
  225. $grid->DeleteRows(0, $grid->GetNumberRows);
  226. $grid->AppendRows(scalar @keys);
  227. for (my $i = 0; $i < @keys; $i++) {
  228. $grid->SetCellValue($i, 0, $keys[$i]);
  229. $grid->SetCellValue($i, 1, $hash->{$keys[$i]});
  230. $grid->SetReadOnly($i, 0, 1);
  231. $self->{rows}{$keys[$i]} = $i;
  232. }
  233. $grid->AutoSize;
  234. $self->{config} = {%{$hash}};
  235. $self->{html}->SetPage(_help($keys[0]));
  236. }
  237. sub getValue {
  238. my ($self, $key) = @_;
  239. return $self->{config}{$key};
  240. }
  241. sub setValue {
  242. my ($self, $key, $value) = @_;
  243. my $i = $self->{rows}{$key};
  244. $self->{grid}->SetCellValue($i, 1, $value);
  245. $self->{config}{$key} = $value;
  246. if ($self->{onChanged}) {
  247. $self->{onChanged}->($key, $value);
  248. }
  249. if ($self->{revertEnableCallback}) {
  250. $self->{revertEnableCallback}->(1);
  251. }
  252. }
  253. sub _onClick {
  254. my ($self, $grid, $event) = @_;
  255. my $row = $event->GetRow;
  256. $self->{html}->SetPage(_help($grid->GetCellValue($row, 0)));
  257. $event->Skip;
  258. }
  259. sub _changed {
  260. my ($self, $grid, $event) = @_;
  261. my $key = $grid->GetCellValue($event->GetRow, 0);
  262. my $value = $grid->GetCellValue($event->GetRow, 1);
  263. $self->{config}{$key} = $value;
  264. $event->Skip;
  265. if ($self->{onChanged}) {
  266. $self->{onChanged}->($key, $value);
  267. }
  268. if ($self->{revertEnableCallback}) {
  269. $self->{revertEnableCallback}->(1);
  270. }
  271. }
  272. sub _help {
  273. my ($name) = @_;
  274. if ($manual eq '') {
  275. return 'Unable to download the manual.';
  276. } else {
  277. my $tmp = quotemeta "<dt class="item"><b>$name";
  278. my ($found) = $manual =~ /<a name="$name"></a>.*?<dl class="primaryList">n(${tmp}.*?)</dl>/s;
  279. $found = "No help available for "$name"." if ($found eq '');
  280. return $found;
  281. }
  282. }
  283. 1;